本地版猜拳游戏(基于TCP socket的编程)

Designed by Rossi


被迫营业的产物,不过最终效果还是不错的

文章目录

  • 本地版猜拳游戏(基于TCP socket的编程)
  • 猜拳介绍
  • 一、运行效果展示
  • 二、代码解析
    • 1.Player
    • 2.PlayerPanel
    • 3.AnswerPanel
    • 4.Table
    • 5.GameServer
    • 6.Demo
  • 三、总结

猜拳介绍

猜拳,又称剪刀石头布,也叫“猜丁壳”,古老而简单,这个游戏的主要目的是为了解决争议,因为三者相互制约,因此不论平局几次,总会有胜负的时候。
游戏规则中,石头克剪刀,剪刀克布,布克石头。
它的起源有两种说法:一种是说起源于中国,主要是由明朝人所写"五杂俎"记载最早剪刀石头布是起源自汉朝的手势令与豁拳。另外一种说法是起源于日本19世纪。到了二十世纪剪刀石头布的游戏开始传到了欧洲与美国,而欧美都称剪刀石头布的游戏是"日本游戏",法国人称剪刀石头布为"jeu Japonais" (意思就是日本游戏)。原因就是因为到了二十世纪,日本人大量西化以及日本人到世界各国游历的原因,也对欧美推广了这个游戏,使得很多欧美人都认为剪刀石头布就是日本的游戏。


一、运行效果展示

因为这里才用的IP是本地的127.0.0.1,所以这里是可以看到两个窗口也可以进行不同的操作。如果想实现联网对战可以找上好朋友,然后把代码中设置的IP更换成双方的IP然后同时运行即可

运行截图如下:

二、代码解析

需要先运行一次Gameserver,然后再运行Demo,才能正确运行,请勿在IDE上重复编译运行
本人的代码是在eclipse编译器上编写的,并且是分块编写,一个包里包含了以下几个类文件

1.Player

首先定义玩家的属性,所以要建立Player类

代码如下:

import javax.swing.*;public class Player {private String playerName,playerIP;private Icon playI;Player(String playerName){setPlayerName(playerName);}public Icon getPlayI() {return playI;}public String getPlayerIP() {return playerIP;}public String getPlayerName() {return playerName;}public void setPlayI(Icon playI) {this.playI = playI;}public void setPlayerIP(String playerIP) {this.playerIP = playerIP;}public void setPlayerName(String playerName) {this.playerName = playerName;}
}

2.PlayerPanel

有了玩家就需要去完善设计界面,便有如下PlayerPanel类

代码如下:

import javax.swing.*;
import java.awt.*;class PlayerPanel extends JPanel{private JButton playerB,answerB;private JLabel playerLable;private Icon playI,answerI;private Player player;PlayerPanel(Player player){this.player=player;setBounds(0,0,120,75);setLayout(null);setBackground(Color.blue);        playerB = new JButton();playerB.setIcon(this.player.getPlayI());playerB.setBounds(5,5,50,50);answerB = new JButton();answerB.setBounds(65,5,50,50);//answerB.setEnabled(false);answerB.setIcon(setAnswerI(0));playerLable = new JLabel();playerLable.setBounds(5,50,100,30);playerLable.setText(this.player.getPlayerName());add(playerB);add(answerB);add(playerLable);validate();}public void reloadPlayer(Player player) {this.player = player;playerB.setIcon(this.player.getPlayI());playerLable.setText(this.player.getPlayerName());validate();}public void reloadAnswerI(int answer){answerB.setIcon(setAnswerI(answer));answerB.revalidate();}public Icon setAnswerI(int playI) {Icon icon;String imageName[]={"石头.png","剪刀.png","布.png"};String imagePath="随机动画.gif";switch (playI){case 1:imagePath = imageName[0];break;case 2:imagePath = imageName[1];break;case 3:imagePath = imageName[2];break;}icon = new ImageIcon(imagePath);validate();return icon;}
}

3.AnswerPanel

有玩家就会有对手,这里同样设置另一个应答客户端AnswerPanel类

代码如下:

import javax.swing.*;public class AnswerPanel extends JPanel {JButton stone,scissors,cloth;String imageName[]={"石头.png","剪刀.png","布.png"};Icon icon[]= new Icon[imageName.length];Box box;AnswerPanel(){setSize(60,300);setVisible(true);for (int i=0;i<icon.length;i++){icon[i]=new ImageIcon(imageName[i]);}stone = new JButton(icon[0]);stone.setSize(50,50);scissors = new JButton(icon[1]);scissors.setSize(50,50);cloth = new JButton(icon[2]);cloth.setSize(50,50);box=Box.createVerticalBox();box.add(stone);box.add(scissors);box.add(cloth);add(box);validate();}
}

以上两个模块就构成了玩家客户机和对手客户机两个窗口

4.Table

细节搞定了,现在需要进行游戏界面设计和连接的建立工作了,所以就有了下面的Table类

代码如下:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;public class Table extends JPanel implements Runnable, ActionListener {Player self,competitor;PlayerPanel playerPanel1, playerPanel2;JButton connection,play;Socket socket=null;DataInputStream in=null;DataOutputStream out=null;Thread thread;boolean isConnect;int answer,result;Table (){setBounds(5,5,400,400);setBackground(Color.PINK);setLayout(null);setVisible(true);isConnect=false;connection=new JButton("连接服务器");connection.setSize(100,40);connection.setLocation(172,400);connection.addActionListener(this);connection.setEnabled(true);play=new JButton("开始");play.setSize(150,40);play.setLocation(150,170);play.addActionListener(this);play.setEnabled(false);self =new Player("我方");competitor =new Player("对手");self.setPlayI(new ImageIcon("我的头像.png"));competitor.setPlayI(new ImageIcon("对手头像.png"));playerPanel1 = new PlayerPanel(self);playerPanel2 = new PlayerPanel(competitor);playerPanel1.setLocation(160,315);playerPanel2.setLocation(160,10);add(playerPanel1);add(playerPanel2);add(connection);add(play);validate();        }public boolean doConnect(){try {socket=new Socket();InetAddress address=InetAddress.getByName("127.0.0.1");InetSocketAddress socketAddress=new InetSocketAddress(address,8888);socket.connect(socketAddress);  //建立连接in=new DataInputStream(socket.getInputStream());out=new DataOutputStream(socket.getOutputStream());return true;} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return false;}public void sendAnswer(int answer) {try {out.writeInt(answer);this.answer=answer;}catch (UnknownHostException e) {e.printStackTrace();}catch (IOException e) {e.printStackTrace();}}public Boolean isServerClose(Socket socket){try{socket.sendUrgentData(0xFF);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信return false;}catch(Exception se){return true;}}public void actionPerformed(ActionEvent e){if(e.getSource()==connection){if (!isServerClose(socket)) {try {socket.close();System.out.println("正在断开连接"+socket.isClosed());isConnect=false;play.setEnabled(false);playerPanel1.reloadAnswerI(0);} catch (IOException ioException) {ioException.printStackTrace();}connection.setText("连接服务器");}else {if (doConnect()){thread = new Thread(this);thread.start();System.out.println("已连接服务器");connection.setText("断开服务器");play.setEnabled(true);play.setText("开始");isConnect=true;}}}if(e.getSource()==play){play.setEnabled(false);play.setText("请出拳");}}public void run() {System.out.println("启动监听");while (true) {try {result = in.readInt();  //堵塞状态,除非读取到信息switch (result){case 2:playerPanel2.reloadAnswerI(((answer+1)%3+1));play.setText("遗憾你输了,再来一局");play.setEnabled(true);break;case 1:playerPanel2.reloadAnswerI(answer);play.setText("双方打平,再来一局");play.setEnabled(true);break;case 0:playerPanel2.reloadAnswerI(((answer)%3+1));play.setText("恭喜你赢了,再来一局");play.setEnabled(true);}System.out.println("收到服务端应答" + result);} catch (IOException e) {break;}            }}
}

5.GameServer

有了连接之后就需要启动线程激活运行,并且加入猜拳的胜负判定机制,因此构造GameServer类来实现

代码如下:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class GameServer{ServerSocket server=null;ServerThread thread;Socket you=null;GameServer (){while(true){if(server==null) {try {server = new ServerSocket(8888);    //启动监听System.out.println("开始监听");} catch (IOException e1) {System.out.println("启动服务器失败");   //ServerSocket对象不能重复创建e1.printStackTrace();//捕捉异常栈堆}}if(server!=null) {try {you = server.accept();System.out.println("客户地址ַ" + you.getInetAddress());} catch (IOException e) {System.out.println("正在等待");}}if(you!=null){//为每个客户启动一个专门的线程thread=new ServerThread(you);thread.start();}elsecontinue;}}public static void main(String[] args) {new GameServer();}}class ServerThread extends Thread{private Socket socket;private DataOutputStream out=null;private DataInputStream in=null;private static int firstAnswer,secondAnswer;private static boolean ready;private int answer,result;private boolean isConnect,isFirst;private String client;synchronized void setFirstAnswer(int firstAnswer){ServerThread.firstAnswer =firstAnswer;}synchronized void setSecondAnswer(int secondAnswer){ServerThread.secondAnswer =secondAnswer;}synchronized int getFirstAnswer(){return firstAnswer;}synchronized int getSecondAnswer(){return secondAnswer;}synchronized void setReady(boolean ready){ServerThread.ready=ready;}ServerThread(Socket t){socket=t;setReady(false);isFirst=false;client=socket.getInetAddress()+":"+socket.getPort();try{in=new DataInputStream(socket.getInputStream());out=new DataOutputStream(socket.getOutputStream());System.out.println("接入客户机"+client);}catch (IOException e){}}public void run(){while(true){isConnect=!isServerClose(socket);if (isConnect){try{System.out.println("准备读取客户机"+client);answer=in.readInt();if (getFirstAnswer()==0){setFirstAnswer(answer);isFirst=true;}else {setSecondAnswer(answer);setReady(true);}}catch (IOException e){System.out.println("客户离开"+client);break;}while (ready==false){try {Thread.sleep(800);} catch (InterruptedException e) {e.printStackTrace();}}match();try{out.writeInt(result);if (isFirst==true)  flush();}catch (IOException e){System.out.println("客户离开"+client);flush();break;}}else {System.out.println("客户离开:"+socket.getInetAddress());break;}}}private void match(){   //返回本线程可得分数,胜利锝2分,打平1分if (isFirst==true){System.out.println("是第一个出拳");System.out.println("second:"+secondAnswer);System.out.println("first:"+firstAnswer);result=firstAnswer-secondAnswer;}else{System.out.println("是第二个出拳");result=secondAnswer-firstAnswer;}switch (result){    case 0:result= 1;break;//相减为零表示双方相同case 1:         case -2:result= 2;break;//相减为1或者-2表示胜利default:result= 0;//相减为1或者-2表示失败}}private synchronized void flush(){firstAnswer=0;secondAnswer=0;isFirst=false;answer=0;setReady(false);}public Boolean isServerClose(Socket socket){try{socket.sendUrgentData(0xFF);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信return false;}catch(Exception se){return true;}}
}

6.Demo

完成以上设计后,最后需要一个主类Demo来完成最后的操作

代码如下:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;public class Demo {public static void main(String[] args) {Play play=new Play("我方");Play play2=new Play("对方");}
}class Play extends JPanelimplements ActionListener {Table table;AnswerPanel answerPanel;JFrame jFrame;Play(String userName){table = new Table();answerPanel=new AnswerPanel();jFrame= new JFrame(userName);jFrame.setTitle(userName);answerPanel.stone.addActionListener(this);answerPanel.scissors.addActionListener(this);answerPanel.cloth.addActionListener(this);jFrame.setBounds(100,100,500,500);jFrame.add(table,BorderLayout.CENTER);jFrame.add(answerPanel,BorderLayout.EAST);jFrame.setVisible(true);jFrame.validate();jFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);}public void actionPerformed(ActionEvent e) {if(e.getSource()==answerPanel.stone) {if (table.isConnect==true && (table.play.getText()=="请出拳")){System.out.println("石头");table.sendAnswer(1);table.playerPanel1.reloadAnswerI(1);table.play.setText("等待对方中");}}else if(e.getSource()==answerPanel.scissors) {if (table.isConnect==true && (table.play.getText()=="请出拳")){System.out.println("剪刀");table.sendAnswer(2);table.playerPanel1.reloadAnswerI(2);table.play.setText("等待对方中");}}if(e.getSource()==answerPanel.cloth) {if (table.isConnect==true && (table.play.getText()=="请出拳")){System.out.println("布");table.sendAnswer(3);table.playerPanel1.reloadAnswerI(3);table.play.setText("等待对方中");}}}
}

三、总结

像GUI界面的设计还可以再进一步去完善,这些就不多讲。当初设计的时候我还想加入一个背景音乐的,但是调试了四次都是没办法调用音乐出来,因此这个想法不得不先放一放。(如果有大佬愿意指点小弟的话还请不吝赐教)
这个东西也花了我不少时间,工程量甚至比我之前做的三子棋还要大。尽管效果和预想不太一样但是最后操作的时候感觉还是不错的。

所有的源代码我已经贴出来了,如果各位看官有什么好的想法也欢迎各位在蒟蒻的评论区下留言

猜拳游戏(基于TCP socket的编程)相关推荐

  1. 基于TCP,Socket编程,模仿腾讯QQ界面,使用Java开发的一款网络聊天工具。QQ_Chat

    代码下载地址 原博客地址 QQ_Chat 基于TCP,Socket编程,模仿腾讯QQ界面,使用Java开发的一款网络聊天工具. (内含报告) 工具: Eclipse.Navicat for MySQL ...

  2. java基础篇18-网络编程的常识和基于TCP协议的编程模型

    1.网络编程的常识   目前主流的网络通讯软件有:微信.QQ.YY.陌陌.探探.飞信.阿里旺旺....   在吗?  1.1 七层网络模型   为了保证数据传递的可靠安全等等,ISO(国际标准委员会组 ...

  3. Python之TCP Socket网络编程

    0 背景 Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网 ...

  4. 江南大学C语言大作业,TCPIP大作业基于TCP的网络通信编程C语言版(江南大学).doc...

    TCPIP大作业基于TCP的网络通信编程C语言版(江南大学).doc TCP/IP协议编程大作业 课题名称 基于TCP的网络通信 专 业 计算机科学与技术 班 级 计算机1206 学 号 103041 ...

  5. TCP socket 一对一编程实例中出现“烫烫烫”的问题

    我在tcp socket一对一聊天实例的编程过程中出现了前几个数据能正常运行,但是超过一定空间后就会出现好多"烫烫烫",这个问题困扰了三天,在这三天我对我的程序改了又改,还是没改对 ...

  6. 远程服务器返回错误: (500) 内部服务器错误。_[源码和文档分享]基于TCP SOCKET实现的远程聊天系统...

    一.实验目的 本次实验需要完成一个实时聊天系统.该系统由聊天客户端和聊天服务器组成.客户端即可以给指定客户端发送信息,也可以把消息广播给所有客户端.通过这个实验,使得学生掌握socket API编程. ...

  7. 基于 TCP Socket 的服务器与客户端的简单连接

    简单的讲下流程: 1. 服务器会创建一个监听 socket, 用来监听客户端的连接请求,接着配置一下监听 socket 的 IP.port.protocol 2. 绑定配置好的信息 以及监听 sock ...

  8. 【猜拳游戏 基于Objective-C语言】

    前言 这是一个猜拳游戏,玩家选择想要出的拳头:1 剪刀 2 石头 3 布, 机器人随机出拳头, 裁判宣布比赛结果,并为胜利者加1分. 一.玩家类Player.h和Player.m两个文件 Player ...

  9. Windows/Linux TCP Socket网络编程简介及测试代码

    典型的网络应用是由一对程序(即客户程序和服务器程序)组成的,它们位于两个不同的端系统中.当运行这两个程序时,创建了一个客户进程和一个服务器进程,同时它们通过从套接字(socket)读出和写入数据在彼此 ...

最新文章

  1. Spring Cloud 覆写远端的配置属性
  2. 第十六届智能车竞赛 | 单车拉力组浅析
  3. 霍夫变换提取线段与圆
  4. linux vg主备机同步,切换VG主备链路(简)
  5. 2013年1季度中国汽车品牌口碑研究报告 ——自主A级车
  6. 4款语音播报来电短信应用[Android]
  7. mysql主主同步冲突_MySQL主主同步主键冲突处理
  8. python虚拟环境管理工具_Python虚拟环境和包管理工具Pipenv的使用详解--看完这一篇就够了...
  9. matlab旋转机械转子故障信号仿真,旋转机械转子不对中故障诊断技术研究解说.docx...
  10. 系统提示一个程序正在被另一个程序调用,如何知道是被哪个程序调用
  11. 使用Angularjs的ng-cloak指令避免页面乱码
  12. Mybatis Mapper自动注入警告的解决方案
  13. 百度文库资料下载总结技巧
  14. vs2010 sp1安装
  15. VMware12虚拟机怎么下载安装?保姆级安装教程,让你一分钟学会
  16. editplus php格式化,让Editplus自动格式化css和js
  17. netty权威指南笔记-以回车换行结尾的消息如何处理半包问题
  18. python时间函数纳秒_python – 获取纳秒级精度的文件修改时间
  19. 用html做相册需要什么,如何快速有效的生成HTML相册?
  20. Photoshop学习(十四):使用快速蒙版

热门文章

  1. 策略产品的进修之路—了解策略和策略产品
  2. 苏宁零售云,“动物凶猛”
  3. 罗胖精选 | 做产品最重要的是格局
  4. Leetcode 1196:最多可以买到的苹果数量(超详细的解法!!!)
  5. 从谷歌(Google)首页变化看互联网十三年风云
  6. C#视频处理,调用强大的ffmpeg
  7. PHP windoews调用OpenOffice实现word/ppt转PDF-附带demo
  8. 判断输入数是奇数还是偶数
  9. 四轴码垛机器人DH模型运动学
  10. NuttX 任务管理