先画出棋盘界面:

class Gb  extends JFrame implements MouseListener ,Runnable {BufferedWriter bw = null;BufferedReader br = null;//文档的流Chess[] chesses = new Chess[17 * 17];//棋子数组,每个网格一个数组TreeMap<Integer,Integer> tm = new TreeMap<>();//key为序号 value为坐标对应的数组indexTreeMap<Integer,Integer> tmTemp;//读取进度时用,点击加载覆盖tmstatic int width = Toolkit.getDefaultToolkit().getScreenSize().width;static int height = Toolkit.getDefaultToolkit().getScreenSize().height;//获取屏幕的分辨率boolean isReading = false;boolean upCanPress = true;boolean downCanPress = false;//用于读取数据的三个变量public Gb() {this.setTitle("五子棋游戏完成版");this.setSize(900, 800);this.setLocation((width - 800) / 2, (height - 800) / 2 );this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setResizable(false);this.setVisible(true);this.repaint();this.addMouseListener(this);}public void paint(Graphics g) {BufferedImage buf = new BufferedImage(900, 800, BufferedImage.TYPE_INT_RGB);//确定界面的大小,以及涂色方式为RGBGraphics g1 = buf.createGraphics();//选项//背景和棋盘底色//http://zhongguose.com/#zhizihuangg1.setColor(new Color(248,232,193));//背景颜色g1.fill3DRect(0, 0, 900, 800, true);//绘色:(起始坐标X,起始坐标Y,结束坐标X,结束坐标Y)g1.setColor(new Color(235,177,13));//棋盘色g1.fill3DRect(60, 60, 680, 680, true);//棋盘线for (int i = 80; i <= 720; i += 40) {g1.setColor(Color.BLACK);g1.drawLine(80, i, 720, i);g1.drawLine(i, 80, i, 720);}//右上角黑白棋//用于提醒下一棋子是什么颜色if(isBlack) {g1.setColor(Color.BLACK);g1.fillOval(770, 50, 30, 30);}else {g1.setColor(Color.WHITE);g1.fillOval(770, 50, 30, 30);}//音乐键//图片在资源文件夹中,打开放在项目文件下try {imageMusic= playMusic ? ImageIO.read(new File("performance.png")) : ImageIO.read(new File("volume-mute.png"));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}g1.drawImage(imageMusic,820,47,null);//功能按键g1.setFont(new Font("微软雅黑",Font.BOLD,15));g1.setColor(new Color(158,204,171));g1.fill3DRect(770, 100, 100, 40,true);g1.fill3DRect(770, 170, 100, 40,true);g1.fill3DRect(770, 240, 100, 40,true);g1.fill3DRect(770, 310, 100, 40,true);g1.fill3DRect(770, 380, 100, 40,true);//读取功能,点击之后可以读档,相关按键在功能开启后出现if(isReading) {g1.fill3DRect(770, 450, 100, 40,upCanPress);g1.fill3DRect(770, 520, 100, 40,true);g1.fill3DRect(770, 590, 100, 40,downCanPress);}g1.fill3DRect(770, 660, 100, 40,true);g1.setColor(Color.BLACK);g1.drawString("重新开始", 780, 125);g1.drawString("悔棋", 780, 195);g1.drawString("认输", 780, 265);g1.drawString("保存进度", 780, 335);g1.drawString("读取进度", 780, 405);if(isReading) {g1.drawString("上一步", 780, 475);g1.drawString("加载游戏", 780, 545);g1.drawString("下一步", 780, 615);}g1.drawString("返回大厅", 780, 685);//棋子填充颜色for(int i = 0 ; i < 17 ; i++ ) {for(int j = 0 ; j < 17 ; j++) {if(chesses[ i + j * 17] != null) {int realX = 70 + i * 40;int realY = 70 + j * 40;//判断棋子颜色 true为黑色  false为白色if (chesses[i + j * 17].isBlack() == true) {g1.setColor(Color.BLACK);g1.fillOval(realX, realY, 20, 20);}else if (chesses[i + j * 17].isBlack() == false) {g1.setColor(Color.WHITE);g1.fillOval(realX, realY, 20, 20);}}}}}

棋子类的构建:

public class Chess {private int x;private int y;private int orderNum;private boolean black;public Chess() {}public Chess(int x, int y, int orderNum, boolean color) {super();this.x = x;this.y = y;this.orderNum = orderNum;this.black = color;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public int getOrderNum() {return orderNum;}public void setOrderNum(int orderNum) {this.orderNum = orderNum;}public boolean isBlack() {return black;}public void setBlack(boolean color) {this.black = color;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Chess other = (Chess) obj;return black == other.black;}}

棋子和棋盘的存储思路:

棋盘是17*17(非标准,当时一拍脑袋决定的),一般来说,用二维数组 chesses[17][17]存储棋盘信息是很符合大脑习惯的,不过二维数组有不方便的地方,直接用chesses[17 * 17]来存储了,其实也很好理解,数组索引对应每个棋子 X + Y * 17(可能需要理解一下),或者由索引反推坐标就是:X = i (数组索引) % 17;     Y = i / 17;。

chesses[17 * 17]是棋盘的存储数据,下一个棋子就会在对应索引新建一个棋子对象,并在对应的坐标绘制棋子图像。

落子的存储是用TreeMap,key为落子顺序(1,2,3,4…),value为棋子的一维数组索引。

这样存储的好处是方便读取数据,读取存档的时候很方便。

当然还可以另一个思路:

因为Chess类中申明了落子顺序OrderNum,直接用ArrayList存储落子信息以及棋盘信息,用ArrayList的方法也很方便。

下棋子:

           //如果游戏结束,canPlay = falseif(canPlay) {//下棋子int x = (e.getX() - 60) / 40;int y = (e.getY() - 60) / 40;if (e.getX() >= 80 && e.getY() >= 80 && e.getX() <= 720 && e.getY() <= 720) {//填充if(chesses[x + y * 17] == null) {chesses[x + y * 17] = new Chess(x,y,countNum++,isBlack);isBlack = !isBlack;isSaved = false;//测试:棋子序号 + 横坐标 + 纵坐标System.out.println(chesses[x + y * 17].getOrderNum() + "..." +chesses[x + y * 17].getX() + "..." + chesses[x + y * 17].getY());//testSystem.out.println(maxLine(chesses[x + y * 17]));}tm.put(chesses[x + y * 17].getOrderNum(), x + y * 17);this.repaint();}else {return;}//判断胜负isWin(maxLine(chesses[x + y * 17]));}

maxLine方法:

米字形判断,每次落子都判断上下左右斜方向的最长连子数。

基本思路:以横向为例,落子后判断索引±4的最长连子,需要注意一个问题,就是棋子在棋盘的边界,需要加一个判断,如果纵坐标变动了(变成另一排),则重新计算maxLine。如果是竖向判断,则需要监控X坐标有无变动;斜向的话,需要监控Y坐标,如果变化为2,重新计算。

//判断最长连子数public int maxLine(Chess chess) {int xLine = 1;int yLine = 1;int rightLine = 1;int leftLine = 1;int max = 1;int index = chess.getX() + chess.getY() * 17;//横向判断 for (int i = index - 4 ; i < index + 4 ; i ++) {if (i > 0 && i < 17*17 - 1 && (i + 1) / 17 - i / 17 == 0 ) {if(chesses[i] != null && chesses[i].equals(chess) && chesses[i + 1] != null && chesses[i + 1].equals(chess)) {xLine++;}else {xLine = 1;continue;}max = xLine > max ? xLine : max;}else {xLine = 1;}}//纵向判断if (max == 5) {return 5;}else {for (int i = index - 4 * 17 ; i < index + 4 * 17 ; i += 17) {if (i > 0 && i < 17*17 - 17 && (i + 17) % 17 - i % 17 == 0 ) {if(chesses[i] != null && chesses[i].equals(chess) && chesses[i + 17] != null && chesses[i + 17].equals(chess)) {yLine++;}else {yLine = 1;continue;}max = yLine > max ? yLine : max;}else {yLine = 1;}}}//斜向\if(max == 5) {return 5;}else {for (int i = index - 4 * 18; i < index + 4 * 18 ; i += 18) {if (i > 0 && i < 17*17 -  18 && (i+ 18) / 17 - i / 17 == 1 ) {if(chesses[i] != null && chesses[i].equals(chess) && chesses[i + 18] != null && chesses[i + 18].equals(chess)) {leftLine++;}else {leftLine = 1;continue;}max = leftLine > max ? leftLine : max;}else {leftLine = 1;}}}// 斜向/if(max == 5) {return 5;}else {for (int i = index - 4 * 16; i < index + 4 * 16 ; i += 16) {if (i > 0 && i < 17*17 -  16 && (i+ 16) / 17 - i / 17 == 1 ) {if(chesses[i] != null && chesses[i].equals(chess) && chesses[i + 16] != null && chesses[i + 16].equals(chess)) {rightLine++;}else {rightLine = 1;continue;}max = rightLine > max ? rightLine : max;}else {rightLine = 1;}}}return max; }

isWin方法:

//判断是否胜利,输入最长连子数public void isWin(int i) {if (i >= 5) {canPlay = false;if(isBlack == true) {JOptionPane.showMessageDialog(this, "白方胜利");}else {JOptionPane.showMessageDialog(this, "黑方胜利");}}}

canPlay用来控制能否下棋,游戏判出胜负后就不能继续落子了,需要点悔棋或者重新开始才能继续。

这样就实现了下棋的基本功能了,至于重新开始,悔棋之类的功能,在单机版很容易实现,之后会po出代码,先将一下稍微有点复杂的读取功能:

先看效果图:

选好文档后,(没有保存文档就乱点然后保存一个)就会弹出“上一步”“加载游戏”“下一步”三个功能按键,“上一步” 和 “下一步”是用来读档的,方便知道落子的顺序,同时也可以选中到想要的进度开始游戏。点击加载就可以从当前画面下的棋盘开始一局游戏了。然后,这三个功能键就会消失,等到再次读取进度的时候再出现。

功能键的画图实现代码在绘图中,功能实现代码如下:

if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 380 && e.getY() <= 420) {//这里是坐标int isYes = JOptionPane.showConfirmDialog(this, "是否读取进度","readload",JOptionPane.YES_NO_OPTION);if(isYes== 0) {isReading = true;readLoad();//定义的一个方法,具体在一下代码块里,作用是弹出一个选择文件的框tmTemp = new TreeMap<>();for(Map.Entry<Integer, Integer> entry : tm.entrySet()) {tmTemp.put(entry.getKey(), entry.getValue());}}}/** 读取中的扩展功能*/if(isReading) {canPlay = false;canPress = false;int SIZE = tm.size();int count = tmTemp.size();//上一步if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 450 && e.getY() <= 490 && upCanPress) {if(count > 0 ) {chesses[tmTemp.get(count)] = null;tmTemp.remove(count-- );isBlack = !isBlack;}//testSystem.out.println(tm+" " + SIZE + "\n" +tmTemp + count );}//加载if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 520 && e.getY() <= 560) {isReading = false;restart();for(Map.Entry<Integer, Integer> entry : tmTemp.entrySet()) {tm.put(entry.getKey(), entry.getValue());chesses[entry.getValue()] = new Chess(entry.getValue() % 17 , entry.getValue() / 17 ,countNum ++ ,isBlack);isBlack = !isBlack;isWin(maxLine(chesses[entry.getValue()]));canPress = true;}this.repaint();}//下一步if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 590 && e.getY() <= 630 && downCanPress) {if(count < SIZE ) {int index = tm.get(++count); chesses[index] = new Chess(index % 17 , index / 17 ,count,isBlack);isBlack = !isBlack;tmTemp.put(count , index);}//testSystem.out.println(tm+" " + SIZE + "\n" +tmTemp + count  );}if(count == SIZE) {downCanPress = false;}else if(count == 0) {upCanPress = false;}else {downCanPress = true;upCanPress = true;}this.repaint();}

readLoad方法:

//读取功能,弹出窗口选择保存文档public void readLoad() {JFileChooser chooser = new JFileChooser();FileNameExtensionFilter filter = new FileNameExtensionFilter("(*.txt)", "txt");chooser.setFileFilter(filter);int option = chooser.showOpenDialog(null);if(option==JFileChooser.APPROVE_OPTION){File file = chooser.getSelectedFile();System.out.println(file.getAbsolutePath());restart();//定义的重开的方法:棋盘清空,存档清空…try {br = new BufferedReader(new FileReader(file));String line = null;while((line = br.readLine()) != null) {String[] arr = line.split(" ");int num = Integer.parseInt(arr[1]);if(chesses[num] == null) {chesses[num] = new Chess(num % 17,num / 17,countNum++,isBlack);isBlack = !isBlack;tm.put(countNum - 1, num);this.repaint();isWin(maxLine(chesses[num]));}else {JOptionPane.showMessageDialog(this, "文件读取错误\r\n棋子重复");break;}}} catch (Exception e1) {e1.printStackTrace();}finally {if(br != null) {try {br.close();} catch (IOException e1) {e1.printStackTrace();}}}isSaved = true;}}

涉及到IO流和弹窗的类的使用,具体怎么存档可以根据自己开发需要进行修改。

读档的时候,因为可能会多次“上一步”和“下一步”,这里选择再新建一个TreeMap用来复制读档,这个TreeMap的作用就是保存完整的读档文件,具体上一步下一步的操作结果是落实在我们之前就新建好的TreeMap来存档文件,这样可以保证重复“上一步”和“下一步”的操作。

等点击“加载游戏”的时候,再用临时的TreeMap复制进棋盘存储数据的TreeMap中。

等无法进行“上一步”或者“下一步”的操作时,会进行一个判断,此时会将无法执行的按键(比如,才开始读档时,是不能点“下一步”的,或者棋盘已经没有棋子的时候,是不能“上一步”的),按键的样式会变灰一点,具体的实现在绘画代码块中,只需要讲按键方法中最后一个值改为false就行,canPress布尔变量就是定义来干这个事情的。

以下是其他功能的实现代码,同样,绘图的实现在最上面的代码块中。

/** 重新开始功能*/if(canPress && e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 100 && e.getY() <= 140 ) {if(canPlay == true) {if(countNum == 1) {JOptionPane.showMessageDialog(this, "棋盘并无棋子");}else {int isYes = JOptionPane.showConfirmDialog(this, "胜负未分,是否重新开始","restart",JOptionPane.YES_NO_OPTION);if(isYes== 0) {restart();}}}else {restart();}}/**悔棋功能*/if(canPress && e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 170 && e.getY() <= 210) {int isYes = JOptionPane.showConfirmDialog(this, "是否悔棋","take back a move",JOptionPane.YES_NO_OPTION);if(isYes== 0) {if(tm.get(1) != null) {canPlay = true;isBlack = !isBlack;isSaved = false;chesses[tm.remove(--countNum)] = null;this.repaint();}else {JOptionPane.showMessageDialog(this, "棋盘没有棋子");}}else {//JOptionPane.showMessageDialog(this, "悔棋失败");}}/** 保存功能:落子顺序和坐标数组序号*/ if(canPress && e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 310 && e.getY() <= 350) {int isYes = JOptionPane.showConfirmDialog(this, "是否保存棋局","saveload",JOptionPane.YES_NO_OPTION);if(isYes == 0) {saveLoad();}}/** 返回大厅*/if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 660 && e.getY() <= 700) {if(isSaved == true) {int isYes = JOptionPane.showConfirmDialog(this, "是否退出","exit",JOptionPane.YES_NO_OPTION);if(isYes== 0) {page = 1;restart();this.repaint();}}else {int isYes = JOptionPane.showConfirmDialog(this, "棋谱未保存,是否退出前保存?","exit",JOptionPane.YES_NO_CANCEL_OPTION);if(isYes== 0) {saveLoad();page = 1;restart();this.repaint();}else if(isYes == 1){page = 1;restart();this.repaint();}else {}}}/** 认输功能*/if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 240 && e.getY() <= 280) {int isYes = JOptionPane.showConfirmDialog(this, "是否认输","give up",JOptionPane.YES_NO_OPTION);if(isYes== 0) {canPlay = false;if(isBlack == true) {JOptionPane.showMessageDialog(this, "白方胜利");}else {JOptionPane.showMessageDialog(this, "黑方胜利");}    }}

方法代码:

//重新开始public void restart() {canPlay = true;isBlack = true;isSaved = false;chesses = new Chess[17 * 17];countNum = 1;tm = new TreeMap<Integer,Integer>();this.repaint();}
//保存功能,弹出窗口保存public void saveLoad() {JFileChooser chooser = new JFileChooser();FileNameExtensionFilter filter = new FileNameExtensionFilter("(*.txt)", "txt");chooser.setFileFilter(filter);int option = chooser.showSaveDialog(null);if(option==JFileChooser.APPROVE_OPTION){  File file = chooser.getSelectedFile();String fileName = chooser.getName(file);if(fileName.indexOf(".txt")==-1){file = new File(chooser.getCurrentDirectory(),fileName+".txt");System.out.println("renamed"); System.out.println(file.getName());}try {bw = new BufferedWriter(new FileWriter(file));for(Map.Entry<Integer,Integer> entry : tm.entrySet()) {bw.write(entry.getKey() + " " + entry.getValue());bw.newLine();bw.flush();}}catch(IOException ee){System.out.println("IO异常");ee.printStackTrace();}finally{if(bw != null) {try {bw.close();} catch (IOException e1) {e1.printStackTrace();}}}isSaved = true;}}

这样基本的单机版就算完成了。因为代码是从完整版里面截下来的,比较乱,不过没关系,最后会有全部的代码汇总。

再来一个难实现的功能就是联网了,(为了实现这个功能熬了半个月的夜,当然现在回想起来也不难,自己基础没打好)。

联网的思路有很多,可以建立一个服务器类,棋盘类的代码只需要完成连接服务器的socket就行,当然服务器的构建就会需要花费很多功夫了,毕竟还有匹配(开房间),禁止其他人加入这些功能需要考虑。

我选择了另一个简单的思路:棋盘类继承Runnable类,重写run方法,等点击联网功能键的时候,开出一个支线程,在线程中开启一个 ServerSocket用来接受另一个客户端发来的信息。

等需要发送信息的时候,调用发送方法,新建socket连接对方服务器,即可完成信息的交互。

这里还需要多一嘴,落子的信息很好理解:落子时,只需要将我的落子的棋子在chesses[]数组中的索引给到对方即可,那功能按键呢?

我选择用常量来代替,棋盘落子只需要用到0到17*17 - 1这个区间,那么从17 * 17开始,就可以定义为功能按键的信息。具体代码:

@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("执行run()");String line = null;try {server = new ServerSocket(Integer.parseInt(yourPort));while(true) {matchsocket = server.accept();System.out.println("连接成功");obr = new BufferedReader(new InputStreamReader(matchsocket.getInputStream()));line = obr.readLine();int inputNum =Integer.parseInt(line.trim());System.out.println("读取数据" + inputNum);translator(inputNum);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}public void send(int i) {try {yoursocket = new Socket(matchIP,Integer.parseInt(matchPort.trim()));obw = new BufferedWriter(new OutputStreamWriter(yoursocket.getOutputStream()));obw.write(String.valueOf(i));obw.newLine();System.out.println("发送数据" + i);obw.flush();obw.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public void translator(int i) {if(ONLINE_DISCONNECT == i) {isFilled = false;yourIP = null;yourPort = null;matchIP = null;matchPort = null;obw = null;obr = null;yoursocket = null;matchsocket = null;server = null;onlineRestart();page = 1;this.repaint();}else if(ONLINE_RESTART_REQUEST == i) {//只能判断胜负后才能重开restartWaitting = true;JOptionPane.showMessageDialog(this, "对手希望再来一局");}else if(ONLINE_RESTART_YES == i) {onlineRestart();int j = random.nextInt(100);myNum = ONLINE_DISCONNECT + j + 1;send(myNum);}else if(ONLINE_REGRATE_REQUEST == i) {regrateCanPress = false;int isYes = JOptionPane.showConfirmDialog(this, "对方请求悔棋,是否同意","take back a move",JOptionPane.YES_NO_OPTION);if(isYes == 0) {send(ONLINE_REGRATE_YES);canPlay = true;isBlack = !isBlack;yourTurn = !yourTurn;isSaved = false;chesses[tm.remove(--countNum)] = null;regrateCanPress = true;this.repaint();}else {send(ONLINE_REGRATE_NO);regrateCanPress = true;}}else if(i > ONLINE_DISCONNECT && i <= ONLINE_DISCONNECT + 100) {yourTurn = myNum > i ? true : false ;isBlack = true;if(yourTurn) {send(ONLINE_MYTURN);JOptionPane.showMessageDialog(this, "执先手");}else {send(ONLINE_YOURTURN);JOptionPane.showMessageDialog(this, "执后手");}}else if(ONLINE_REGRATE_YES == i) {canPlay = true;isBlack = !isBlack;yourTurn = !yourTurn;isSaved = false;chesses[tm.remove(--countNum)] = null;regrateCanPress = true;this.repaint();}else if(ONLINE_REGRATE_NO == i) {JOptionPane.showMessageDialog(this, "对方不同意悔棋");regrateCanPress = true;}else if(ONLINE_SURRENDER == i) {canPlay = false;JOptionPane.showMessageDialog(this, "胜利:对方认输");}else if(i >= 0 && i < 17 * 17) {chesses[i]  = new Chess(i % 17 , i / 17, countNum++ , isBlack);onlineIsWin(maxLine(chesses[i]));isBlack = !isBlack;yourTurn = !yourTurn;isSaved = false;tm.put(chesses[i].getOrderNum(), i);this.repaint();}else if(ONLINE_MYTURN == i) {yourTurn = false;isBlack = true;}else if(ONLINE_YOURTURN == i) {yourTurn = true;isBlack = yourTurn;}else if(ONLINE_WIN == i) {JOptionPane.showMessageDialog(this, "游戏结束");}}

三个方法,分别用来实现[开启服务器][发送信息]和[翻译信息]。

之后,我们只需要在单机版上做出一点调整即可,每次对棋盘做出修改的时候,将相应的信息传递给对方,对方通过translator()方法翻译出来,在棋盘上做出相应的动作即可。

全部的代码在这:

这是主类棋盘类,几乎所有的功能都在这里实现(按理说不应该这样……):

package mygobang;import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;import javax.imageio.ImageIO;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.SourceDataLine;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;class Gb  extends JFrame implements MouseListener ,Runnable {/*** */private static final long serialVersionUID = 1L;JLabel label;BufferedImage imageMusic = null ;BufferedWriter bw = null;BufferedReader br = null;//文档的流Thread onlineThread = new Thread(this);BufferedReader obr = null;BufferedWriter obw = null;//联网的流Chess[] chesses = new Chess[17 * 17];TreeMap<Integer,Integer> tm = new TreeMap<>();//key为序号 value为坐标对应的数组indexTreeMap<Integer,Integer> tmTemp;//读取进度时用,点击加载覆盖tmstatic int width = Toolkit.getDefaultToolkit().getScreenSize().width;static int height = Toolkit.getDefaultToolkit().getScreenSize().height;boolean isReading = false;boolean upCanPress = true;boolean downCanPress = false;static boolean hasWindow = false;static boolean threadIsStart = false;static String yourIP = null;static String yourPort = null;static String matchIP = null;static String matchPort = null;private int page = 1;//1 为开始界面。2为单机界面。3为联机界面。ServerSocket server = null;Socket yoursocket = null , matchsocket = null;Random random = new Random();boolean yourTurn = false;boolean restartWaitting = false;boolean restartCanPress = true;boolean regrateCanPress = true;public static final int ONLINE_RESTART_REQUEST = 17 * 17;public static final int ONLINE_RESTART_YES = 17 * 17 + 1;public static final int ONLINE_REGRATE_REQUEST = 17 * 17 + 2;public static final int ONLINE_REGRATE_YES = 17 * 17 + 3;public static final int ONLINE_REGRATE_NO = 17 * 17 + 4;public static final int ONLINE_SURRENDER = 17 * 17 + 5;public static final int ONLINE_MYTURN = 17 * 17 + 6;public static final int ONLINE_YOURTURN = 17 * 17 + 7;public static final int ONLINE_WIN = 17 * 17 + 8;public static final int ONLINE_DISCONNECT = 404;int myNum ;public Gb() {this.setTitle("五子棋游戏未完成版");this.setSize(900, 800);this.setLocation((width - 800) / 2, (height - 800) / 2 );this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setResizable(false);this.setVisible(true);this.repaint();this.addMouseListener(this);while(true) {this.music();}}//画棋盘public void paint(Graphics g) {BufferedImage buf = new BufferedImage(900, 800, BufferedImage.TYPE_INT_RGB);Graphics g1 = buf.createGraphics();/*** 开始界面*/if(page == 1 ) {//背景和棋盘底色//http://zhongguose.com/#zhizihuangg1.setColor(new Color(248,232,193));//背景g1.fill3DRect(0, 0, 900, 800, true);g1.setColor(new Color(158,204,171));g1.fill3DRect(200, 300, 200, 200,true);g1.fill3DRect(550, 300, 200, 200,true);BufferedImage game = null;BufferedImage people = null;try {game = ImageIO.read(new File("game1.png"));people =ImageIO.read(new File("people1.png"));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}g1.drawImage(game,260,360,null);g1.drawImage(people,610,360,null);try {imageMusic= playMusic ? ImageIO.read(new File("performance.png")) : ImageIO.read(new File("volume-mute.png"));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}g1.drawImage(imageMusic,820,47,null);}else if (page == 2 ) {//选项//背景和棋盘底色//http://zhongguose.com/#zhizihuangg1.setColor(new Color(248,232,193));//背景g1.fill3DRect(0, 0, 900, 800, true);g1.setColor(new Color(235,177,13));//棋盘色g1.fill3DRect(60, 60, 680, 680, true);//棋盘线for (int i = 80; i <= 720; i += 40) {g1.setColor(Color.BLACK);g1.drawLine(80, i, 720, i);g1.drawLine(i, 80, i, 720);}//右上角黑白棋if(isBlack) {g1.setColor(Color.BLACK);g1.fillOval(770, 50, 30, 30);}else {g1.setColor(Color.WHITE);g1.fillOval(770, 50, 30, 30);}//音乐键try {imageMusic= playMusic ? ImageIO.read(new File("performance.png")) : ImageIO.read(new File("volume-mute.png"));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}g1.drawImage(imageMusic,820,47,null);//功能按键g1.setFont(new Font("微软雅黑",Font.BOLD,15));g1.setColor(new Color(158,204,171));g1.fill3DRect(770, 100, 100, 40,true);g1.fill3DRect(770, 170, 100, 40,true);g1.fill3DRect(770, 240, 100, 40,true);g1.fill3DRect(770, 310, 100, 40,true);g1.fill3DRect(770, 380, 100, 40,true);if(isReading) {g1.fill3DRect(770, 450, 100, 40,upCanPress);g1.fill3DRect(770, 520, 100, 40,true);g1.fill3DRect(770, 590, 100, 40,downCanPress);}g1.fill3DRect(770, 660, 100, 40,true);g1.setColor(Color.BLACK);g1.drawString("重新开始", 780, 125);g1.drawString("悔棋", 780, 195);g1.drawString("认输", 780, 265);g1.drawString("保存进度", 780, 335);g1.drawString("读取进度", 780, 405);if(isReading) {g1.drawString("上一步", 780, 475);g1.drawString("加载游戏", 780, 545);g1.drawString("下一步", 780, 615);}g1.drawString("返回大厅", 780, 685);//棋子填充颜色for(int i = 0 ; i < 17 ; i++ ) {for(int j = 0 ; j < 17 ; j++) {if(chesses[ i + j * 17] != null) {int realX = 70 + i * 40;int realY = 70 + j * 40;//判断棋子颜色 true为黑色  false为白色if (chesses[i + j * 17].isBlack() == true) {g1.setColor(Color.BLACK);g1.fillOval(realX, realY, 20, 20);}else if (chesses[i + j * 17].isBlack() == false) {g1.setColor(Color.WHITE);g1.fillOval(realX, realY, 20, 20);}}}}}else/* page == 3  */ {//选项//背景和棋盘底色//http://zhongguose.com/#zhizihuangg1.setColor(new Color(248,232,193));//背景g1.fill3DRect(0, 0, 900, 800, true);g1.setColor(new Color(235,177,13));//棋盘色g1.fill3DRect(60, 60, 680, 680, true);//棋盘线for (int i = 80; i <= 720; i += 40) {g1.setColor(Color.BLACK);g1.drawLine(80, i, 720, i);g1.drawLine(i, 80, i, 720);}//右上角黑白棋if(isBlack) {g1.setColor(Color.BLACK);g1.fillOval(770, 50, 30, 30);}else {g1.setColor(Color.WHITE);g1.fillOval(770, 50, 30, 30);}//音乐键try {imageMusic= playMusic ? ImageIO.read(new File("performance.png")) : ImageIO.read(new File("volume-mute.png"));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}g1.drawImage(imageMusic,820,47,null);//功能按键g1.setFont(new Font("微软雅黑",Font.BOLD,15));g1.setColor(new Color(158,204,171));g1.fill3DRect(770, 100, 100, 40,true);g1.fill3DRect(770, 170, 100, 40,true);g1.fill3DRect(770, 240, 100, 40,true);g1.fill3DRect(770, 310, 100, 40,true);g1.fill3DRect(770, 660, 100, 40,true);g1.setColor(Color.BLACK);//188,132,168g1.drawString("重新开始", 780, 125);g1.drawString("悔棋", 780, 195);g1.drawString("认输", 780, 265);g1.drawString("保存进度", 780, 335);g1.drawString("返回大厅", 780, 685);//棋子填充颜色for(int i = 0 ; i < 17 ; i++ ) {for(int j = 0 ; j < 17 ; j++) {if(chesses[ i + j * 17] != null) {int realX = 70 + i * 40;int realY = 70 + j * 40;//判断棋子颜色 true为黑色  false为白色if (chesses[i + j * 17].isBlack() == true) {g1.setColor(Color.BLACK);g1.fillOval(realX, realY, 20, 20);}else if (chesses[i + j * 17].isBlack() == false) {g1.setColor(Color.WHITE);g1.fillOval(realX, realY, 20, 20);}}}}}g.drawImage(buf, 0 , 0 ,this);}//鼠标点击下棋子boolean canPlay = true;boolean isBlack = true;boolean isSaved = false;boolean canPress = true;static boolean isFilled = false;int countNum = 1;public void mousePressed(MouseEvent e) {/** 打开音乐,关闭音乐*/if(e.getX() >= 820 && e.getX() <= 850 && e.getY() >= 20 && e.getY() <= 80) {playMusic =!playMusic;this.repaint();}/*** 三个页面  page 1,2,3  */if (page == 1 && !hasWindow) {//人机按钮if(e.getX() >= 200 && e.getX() <= 400 && e.getY() >= 300 && e.getY() <= 500) {page = 2;this.repaint();}//联网对战按钮if(e.getX() >= 550 && e.getX() <= 750 && e.getY() >= 300 && e.getY() <= 500) {page = 3;hasWindow = true;this.repaint();new ComponentInWindow();int i = random.nextInt(100);myNum = ONLINE_DISCONNECT + i + 1;System.out.println("随机数是" + myNum);}}else if(page == 2 && !hasWindow) {/** 重新开始功能*/if(canPress && e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 100 && e.getY() <= 140 ) {if(canPlay == true) {if(countNum == 1) {JOptionPane.showMessageDialog(this, "棋盘并无棋子");}else {int isYes = JOptionPane.showConfirmDialog(this, "胜负未分,是否重新开始","restart",JOptionPane.YES_NO_OPTION);if(isYes== 0) {restart();}}}else {restart();}}/**悔棋功能*/if(canPress && e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 170 && e.getY() <= 210) {int isYes = JOptionPane.showConfirmDialog(this, "是否悔棋","take back a move",JOptionPane.YES_NO_OPTION);if(isYes== 0) {if(tm.get(1) != null) {canPlay = true;isBlack = !isBlack;isSaved = false;chesses[tm.remove(--countNum)] = null;this.repaint();}else {JOptionPane.showMessageDialog(this, "棋盘没有棋子");}}else {//JOptionPane.showMessageDialog(this, "悔棋失败");}}/** 保存功能:落子顺序和坐标数组序号*/    if(canPress && e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 310 && e.getY() <= 350) {int isYes = JOptionPane.showConfirmDialog(this, "是否保存棋局","saveload",JOptionPane.YES_NO_OPTION);if(isYes == 0) {saveLoad();}}/** 读取进度功能*/if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 380 && e.getY() <= 420) {int isYes = JOptionPane.showConfirmDialog(this, "是否读取进度","readload",JOptionPane.YES_NO_OPTION);if(isYes== 0) {isReading = true;readLoad();tmTemp = new TreeMap<>();for(Map.Entry<Integer, Integer> entry : tm.entrySet()) {tmTemp.put(entry.getKey(), entry.getValue());}}}/** 读取中的扩展功能*/if(isReading) {canPlay = false;canPress = false;int SIZE = tm.size();int count = tmTemp.size();//上一步if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 450 && e.getY() <= 490 && upCanPress) {if(count > 0 ) {chesses[tmTemp.get(count)] = null;tmTemp.remove(count-- );isBlack = !isBlack;}//testSystem.out.println(tm+" " + SIZE + "\n" +tmTemp + count );}//加载if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 520 && e.getY() <= 560) {isReading = false;restart();for(Map.Entry<Integer, Integer> entry : tmTemp.entrySet()) {tm.put(entry.getKey(), entry.getValue());chesses[entry.getValue()] = new Chess(entry.getValue() % 17 , entry.getValue() / 17 ,countNum ++ ,isBlack);isBlack = !isBlack;isWin(maxLine(chesses[entry.getValue()]));canPress = true;}this.repaint();}//下一步if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 590 && e.getY() <= 630 && downCanPress) {if(count < SIZE ) {int index = tm.get(++count); chesses[index] = new Chess(index % 17 , index / 17 ,count,isBlack);isBlack = !isBlack;tmTemp.put(count , index);}//testSystem.out.println(tm+" " + SIZE + "\n" +tmTemp + count  );}if(count == SIZE) {downCanPress = false;}else if(count == 0) {upCanPress = false;}else {downCanPress = true;upCanPress = true;}this.repaint();}/** 返回大厅*/if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 660 && e.getY() <= 700) {if(isSaved == true) {int isYes = JOptionPane.showConfirmDialog(this, "是否退出","exit",JOptionPane.YES_NO_OPTION);if(isYes== 0) {page = 1;restart();this.repaint();}}else {int isYes = JOptionPane.showConfirmDialog(this, "棋谱未保存,是否退出前保存?","exit",JOptionPane.YES_NO_CANCEL_OPTION);if(isYes== 0) {saveLoad();page = 1;restart();this.repaint();}else if(isYes == 1){page = 1;restart();this.repaint();}else {}}}if(canPlay) {/** 认输功能*/if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 240 && e.getY() <= 280) {int isYes = JOptionPane.showConfirmDialog(this, "是否认输","give up",JOptionPane.YES_NO_OPTION);if(isYes== 0) {canPlay = false;if(isBlack == true) {JOptionPane.showMessageDialog(this, "白方胜利");}else {JOptionPane.showMessageDialog(this, "黑方胜利");}    }}//下棋子int x = (e.getX() - 60) / 40;int y = (e.getY() - 60) / 40;if (e.getX() >= 80 && e.getY() >= 80 && e.getX() <= 720 && e.getY() <= 720) {//填充if(chesses[x + y * 17] == null) {chesses[x + y * 17] = new Chess(x,y,countNum++,isBlack);isBlack = !isBlack;isSaved = false;//测试:棋子序号 + 横坐标 + 纵坐标System.out.println(chesses[x + y * 17].getOrderNum() + "..." +chesses[x + y * 17].getX() + "..." + chesses[x + y * 17].getY());//testSystem.out.println(maxLine(chesses[x + y * 17]));}tm.put(chesses[x + y * 17].getOrderNum(), x + y * 17);this.repaint();}else {return;}//判断胜负isWin(maxLine(chesses[x + y * 17]));}}else if(page == 3 && !hasWindow) {System.out.println("点击");if(!hasWindow && !threadIsStart) {Thread t = new Thread(this);t.start();System.out.println("线程开启");send(myNum);threadIsStart = true;}//         if(threadIsStart) {
//
//          }/** 重新开始功能*/if(canPress && restartCanPress && e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 100 && e.getY() <= 140 ) {if(canPlay) {JOptionPane.showMessageDialog(this, "胜负未分,请勿放弃!");}else {if(!restartWaitting) {send(ONLINE_RESTART_REQUEST);restartWaitting = true;restartCanPress = false;}else {int i = random.nextInt(100);myNum = ONLINE_DISCONNECT + i + 1;send(ONLINE_RESTART_YES);send(myNum);onlineRestart();}}}/**悔棋功能*/if(canPress && regrateCanPress && !yourTurn && e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 170 && e.getY() <= 210) {int isYes = JOptionPane.showConfirmDialog(this, "是否悔棋","take back a move",JOptionPane.YES_NO_OPTION);if(isYes== 0) {if(tm.get(1) != null) {regrateCanPress = false;send(ONLINE_REGRATE_REQUEST);  }else {JOptionPane.showMessageDialog(this, "棋盘没有棋子");}}}/** 保存功能:落子顺序和坐标数组序号*/ if(canPress && e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 310 && e.getY() <= 350) {int isYes = JOptionPane.showConfirmDialog(this, "是否保存棋局","saveload",JOptionPane.YES_NO_OPTION);if(isYes == 0) {saveLoad();}}/** 返回大厅*/if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 660 && e.getY() <= 700) {if(isSaved == true) {int isYes = JOptionPane.showConfirmDialog(this, "是否退出","exit",JOptionPane.YES_NO_OPTION);if(isYes== 0) {isFilled = false;yourIP = null;yourPort = null;matchIP = null;matchPort = null;obw = null;obr = null;yoursocket = null;matchsocket = null;server = null;threadIsStart = false;onlineRestart();page = 1;this.repaint();send(ONLINE_DISCONNECT);}}else {int isYes = JOptionPane.showConfirmDialog(this, "棋谱未保存,是否退出前保存?","exit",JOptionPane.YES_NO_CANCEL_OPTION);if(isYes== 0) {saveLoad();isFilled = false;yourIP = null;yourPort = null;matchIP = null;matchPort = null;obw = null;obr = null;yoursocket = null;matchsocket = null;server = null;threadIsStart = false;onlineRestart();page = 1;this.repaint();send(ONLINE_DISCONNECT);}else if(isYes == 1){isFilled = false;yourIP = null;yourPort = null;matchIP = null;matchPort = null;obw = null;obr = null;yoursocket = null;matchsocket = null;server = null;threadIsStart = false;onlineRestart();page = 1;this.repaint();send(ONLINE_DISCONNECT);}else {}}}if(canPlay) {/** 认输功能*/if(e.getX() >= 770 && e.getX() <= 870 && e.getY() >= 240 && e.getY() <= 280) {int isYes = JOptionPane.showConfirmDialog(this, "是否认输","give up",JOptionPane.YES_NO_OPTION);if(isYes== 0) {canPlay = false;send(ONLINE_SURRENDER);JOptionPane.showMessageDialog(this, "认输");}}//下棋子int x = (e.getX() - 60) / 40;int y = (e.getY() - 60) / 40;if (yourTurn && e.getX() >= 80 && e.getY() >= 80 && e.getX() <= 720 && e.getY() <= 720) {//填充if(chesses[x + y * 17] == null) {chesses[x + y * 17] = new Chess(x,y,countNum++,isBlack);send(x + y * 17);isBlack = !isBlack;yourTurn = !yourTurn;isSaved = false;//测试:棋子序号 + 横坐标 + 纵坐标System.out.println(chesses[x + y * 17].getOrderNum() + "..." +chesses[x + y * 17].getX() + "..." + chesses[x + y * 17].getY());//testSystem.out.println(maxLine(chesses[x + y * 17]));}tm.put(chesses[x + y * 17].getOrderNum(), x + y * 17);this.repaint();}else {return;}//判断胜负onlineIsWin(maxLine(chesses[x + y * 17]));}}}boolean playMusic = true;public void music() {try {AudioInputStream ais = AudioSystem.getAudioInputStream(new File("UGmusic.wav"));AudioFormat aif = ais.getFormat();final SourceDataLine sdl;DataLine.Info info = new DataLine.Info(SourceDataLine.class, aif);sdl = (SourceDataLine) AudioSystem.getLine(info);sdl.open(aif);sdl.start();FloatControl fc = (FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN);// value可以用来设置音量,从0-2.0double value = 2;float dB = (float) (Math.log(value == 0.0 ? 0.0001 : value) / Math.log(10.0) * 20.0);fc.setValue(dB);int nByte = 0;final int SIZE = 1024 * 64;byte[] buffer = new byte[SIZE];while (nByte != -1) {// 判断 播放/暂停 状态if(playMusic) {nByte = ais.read(buffer, 0, SIZE);sdl.write(buffer, 0, nByte);}else {nByte = ais.read(buffer, 0, 0);}}sdl.stop();} catch (Exception e) {e.printStackTrace();}}//判断最长连子数public int maxLine(Chess chess) {int xLine = 1;int yLine = 1;int rightLine = 1;int leftLine = 1;int max = 1;int index = chess.getX() + chess.getY() * 17;//横向判断 for (int i = index - 4 ; i < index + 4 ; i ++) {if (i > 0 && i < 17*17 - 1 && (i + 1) / 17 - i / 17 == 0 ) {if(chesses[i] != null && chesses[i].equals(chess) && chesses[i + 1] != null && chesses[i + 1].equals(chess)) {xLine++;}else {xLine = 1;continue;}max = xLine > max ? xLine : max;}else {xLine = 1;}}//纵向判断if (max == 5) {return 5;}else {for (int i = index - 4 * 17 ; i < index + 4 * 17 ; i += 17) {if (i > 0 && i < 17*17 - 17 && (i + 17) % 17 - i % 17 == 0 ) {if(chesses[i] != null && chesses[i].equals(chess) && chesses[i + 17] != null && chesses[i + 17].equals(chess)) {yLine++;}else {yLine = 1;continue;}max = yLine > max ? yLine : max;}else {yLine = 1;}}}//斜向\if(max == 5) {return 5;}else {for (int i = index - 4 * 18; i < index + 4 * 18 ; i += 18) {if (i > 0 && i < 17*17 -  18 && (i+ 18) / 17 - i / 17 == 1 ) {if(chesses[i] != null && chesses[i].equals(chess) && chesses[i + 18] != null && chesses[i + 18].equals(chess)) {leftLine++;}else {leftLine = 1;continue;}max = leftLine > max ? leftLine : max;}else {leftLine = 1;}}}// 斜向/if(max == 5) {return 5;}else {for (int i = index - 4 * 16; i < index + 4 * 16 ; i += 16) {if (i > 0 && i < 17*17 -  16 && (i+ 16) / 17 - i / 17 == 1 ) {if(chesses[i] != null && chesses[i].equals(chess) && chesses[i + 16] != null && chesses[i + 16].equals(chess)) {rightLine++;}else {rightLine = 1;continue;}max = rightLine > max ? rightLine : max;}else {rightLine = 1;}}}return max;  }//重新开始public void restart() {canPlay = true;isBlack = true;isSaved = false;chesses = new Chess[17 * 17];countNum = 1;tm = new TreeMap<Integer,Integer>();this.repaint();}//联网重新开始public void onlineRestart() {canPlay = true;isBlack = true;isSaved = false;chesses = new Chess[17 * 17];countNum = 1;tm = new TreeMap<Integer,Integer>();restartWaitting = false;restartCanPress = true;this.repaint();}//判断是否胜利,输入最长连子数public void isWin(int i) {if (i >= 5) {canPlay = false;if(isBlack == true) {JOptionPane.showMessageDialog(this, "白方胜利");}else {JOptionPane.showMessageDialog(this, "黑方胜利");}}}public void onlineIsWin(int i) {if (i >= 5) {canPlay = false;if(yourTurn) {JOptionPane.showMessageDialog(this, "游戏结束!");}else {send(ONLINE_WIN);}}}//保存功能,弹出窗口保存public void saveLoad() {JFileChooser chooser = new JFileChooser();FileNameExtensionFilter filter = new FileNameExtensionFilter("(*.txt)", "txt");chooser.setFileFilter(filter);int option = chooser.showSaveDialog(null);if(option==JFileChooser.APPROVE_OPTION){ File file = chooser.getSelectedFile();String fileName = chooser.getName(file);if(fileName.indexOf(".txt")==-1){file = new File(chooser.getCurrentDirectory(),fileName+".txt");System.out.println("renamed"); System.out.println(file.getName());}try {bw = new BufferedWriter(new FileWriter(file));for(Map.Entry<Integer,Integer> entry : tm.entrySet()) {bw.write(entry.getKey() + " " + entry.getValue());bw.newLine();bw.flush();}}catch(IOException ee){System.out.println("IO异常");ee.printStackTrace();}finally{if(bw != null) {try {bw.close();} catch (IOException e1) {e1.printStackTrace();}}}isSaved = true;}}//读取功能,弹出窗口选择保存文档public void readLoad() {JFileChooser chooser = new JFileChooser();FileNameExtensionFilter filter = new FileNameExtensionFilter("(*.txt)", "txt");chooser.setFileFilter(filter);int option = chooser.showOpenDialog(null);if(option==JFileChooser.APPROVE_OPTION){File file = chooser.getSelectedFile();System.out.println(file.getAbsolutePath());restart();try {br = new BufferedReader(new FileReader(file));String line = null;while((line = br.readLine()) != null) {String[] arr = line.split(" ");int num = Integer.parseInt(arr[1]);if(chesses[num] == null) {chesses[num] = new Chess(num % 17,num / 17,countNum++,isBlack);isBlack = !isBlack;tm.put(countNum - 1, num);this.repaint();isWin(maxLine(chesses[num]));}else {JOptionPane.showMessageDialog(this, "文件读取错误\r\n棋子重复");break;}}} catch (Exception e1) {e1.printStackTrace();}finally {if(br != null) {try {br.close();} catch (IOException e1) {e1.printStackTrace();}}}isSaved = true;}}public void translator(int i) {if(ONLINE_DISCONNECT == i) {isFilled = false;yourIP = null;yourPort = null;matchIP = null;matchPort = null;obw = null;obr = null;yoursocket = null;matchsocket = null;server = null;onlineRestart();page = 1;this.repaint();}else if(ONLINE_RESTART_REQUEST == i) {//只能判断胜负后才能重开restartWaitting = true;JOptionPane.showMessageDialog(this, "对手希望再来一局");}else if(ONLINE_RESTART_YES == i) {onlineRestart();int j = random.nextInt(100);myNum = ONLINE_DISCONNECT + j + 1;send(myNum);}else if(ONLINE_REGRATE_REQUEST == i) {regrateCanPress = false;int isYes = JOptionPane.showConfirmDialog(this, "对方请求悔棋,是否同意","take back a move",JOptionPane.YES_NO_OPTION);if(isYes == 0) {send(ONLINE_REGRATE_YES);canPlay = true;isBlack = !isBlack;yourTurn = !yourTurn;isSaved = false;chesses[tm.remove(--countNum)] = null;regrateCanPress = true;this.repaint();}else {send(ONLINE_REGRATE_NO);regrateCanPress = true;}}else if(i > ONLINE_DISCONNECT && i <= ONLINE_DISCONNECT + 100) {yourTurn = myNum > i ? true : false ;isBlack = true;if(yourTurn) {send(ONLINE_MYTURN);JOptionPane.showMessageDialog(this, "执先手");}else {send(ONLINE_YOURTURN);JOptionPane.showMessageDialog(this, "执后手");}}else if(ONLINE_REGRATE_YES == i) {canPlay = true;isBlack = !isBlack;yourTurn = !yourTurn;isSaved = false;chesses[tm.remove(--countNum)] = null;regrateCanPress = true;this.repaint();}else if(ONLINE_REGRATE_NO == i) {JOptionPane.showMessageDialog(this, "对方不同意悔棋");regrateCanPress = true;}else if(ONLINE_SURRENDER == i) {canPlay = false;JOptionPane.showMessageDialog(this, "胜利:对方认输");}else if(i >= 0 && i < 17 * 17) {chesses[i]  = new Chess(i % 17 , i / 17, countNum++ , isBlack);onlineIsWin(maxLine(chesses[i]));isBlack = !isBlack;yourTurn = !yourTurn;isSaved = false;tm.put(chesses[i].getOrderNum(), i);this.repaint();}else if(ONLINE_MYTURN == i) {yourTurn = false;isBlack = true;}else if(ONLINE_YOURTURN == i) {yourTurn = true;isBlack = yourTurn;}else if(ONLINE_WIN == i) {JOptionPane.showMessageDialog(this, "游戏结束");}}public void send(int i) {try {yoursocket = new Socket(matchIP,Integer.parseInt(matchPort.trim()));obw = new BufferedWriter(new OutputStreamWriter(yoursocket.getOutputStream()));obw.write(String.valueOf(i));obw.newLine();System.out.println("发送数据" + i);obw.flush();obw.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("执行run()");String line = null;try {server = new ServerSocket(Integer.parseInt(yourPort));while(true) {matchsocket = server.accept();System.out.println("连接成功");obr = new BufferedReader(new InputStreamReader(matchsocket.getInputStream()));line = obr.readLine();int inputNum =Integer.parseInt(line.trim());System.out.println("读取数据" + inputNum);translator(inputNum);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}@Overridepublic void mouseClicked(MouseEvent e) {}@Overridepublic void mouseReleased(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseEntered(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseExited(MouseEvent e) {// TODO Auto-generated method stub}}

新建一个棋子类:

package mygobang;public class Chess {private int x;private int y;private int orderNum;private boolean black;public Chess() {}public Chess(int x, int y, int orderNum, boolean color) {super();this.x = x;this.y = y;this.orderNum = orderNum;this.black = color;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public int getOrderNum() {return orderNum;}public void setOrderNum(int orderNum) {this.orderNum = orderNum;}public boolean isBlack() {return black;}public void setBlack(boolean color) {this.black = color;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Chess other = (Chess) obj;return black == other.black;}}

联网时用到的一个弹窗类:

package mygobang;import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;public class ComponentInWindow extends JFrame implements ActionListener {JTextField text1,text2,text3,text4;JButton button;public ComponentInWindow() {init();setVisible(true);this.setResizable(false);this.setBounds(0, 0, 320, 150);this.setTitle("网络链接");this.setLocation((Gb.width - 320) / 2, (Gb.height - 150) / 2 );setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);button.addActionListener(this);add(button);}public void init() {setLayout(new FlowLayout()); // 设置布局add(new JLabel("你的IP:"));text1 = new JTextField(10);add(text1);add(new JLabel("你的端口:"));text2 = new JTextField(10);add(text2);add(new JLabel("对手IP:"));text3 = new JTextField(10);add(text3);add(new JLabel("对手端口:"));text4 = new JTextField(10);add(text4);add(new JLabel("按钮:"));button = new JButton("开始联机");add(button);}@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubGb.yourIP = text1.getText();Gb.yourPort = text2.getText();Gb.matchIP = text3.getText();Gb.matchPort = text4.getText();if(!Gb.yourIP.equals("") && !Gb.yourPort.equals("") && !Gb.matchIP.equals("") && !Gb.matchPort.equals("")) {Gb.hasWindow = false;Gb.isFilled = true;this.dispose();}else {JOptionPane.showMessageDialog(this, "请输入IP和端口");}}
}

执行main类:

package mygobang;public class Run  {public static void main(String[] args) {new Gb();}
}

最后给个效果图:

这是第一页,左边单机,右边联网。右上角是背景音乐,点一下可以暂停,同时图片会换。

单机的就是封面了,再来个联网的:

输入完毕后就可以开始游戏了。(局域网)

没有点击开始联机,小窗口是关不掉的,同时棋盘也无法进行操作。

代码源文件和用到的图片音乐都上传到云了,需要自取:

链接: https://pan.baidu.com/s/1gg17ibt9eInbJO8GEgZ5ow

提取码: wfnu

当然,肯定也有做五子棋完成作业的小伙伴,除了特定的IO流弹窗类绘图类这种,尽量看了之后自己手打哈。

Java五子棋(局域网)相关推荐

  1. java五子棋实训训心得,java五子棋实习报告

    java五子棋实习报告 Java 程序设计基础 实习报告 课程名称 Java 程序设计基础 实习题目 java 五子棋 专 业 班 级 学 号 学生姓名 指导教师 Java 实习报告 一.一.J JA ...

  2. 基于tutk方案的p2p源码_基于JAVA的局域网文件共享平台P2P实训项目源码(毕业设计 课程设计)...

    [实例简介] 基于JAVA的局域网文件共享平台P2P实训项目源码(毕业设计 课程设计). 可直接运行.做毕业设计.课程设计或者想研究下技术的可以下载学习.需要更多资源的可以关注我. [实例截图] [核 ...

  3. Java基于局域网(LAN)的聊天室软件-内附源码

    程序简介 一款基于Java的局域网下实时通信软件(聊天室).界面使用swing. 功能描述 提供"聊天主题"进入相应聊天室. ​ 用户登录时输入任意主题名称即可进入对应主题. 提供 ...

  4. Java五子棋最全教程

    Java五子棋最全教程 Ps:首先当我们做一个项目时应该培养这样一种思维即这个项目怎么开展,分为哪几个功能,这每个功能又该分为哪几步去实现,只有确定了基本路线,才有利于我们设计程序的基本结构,也让我们 ...

  5. Java五子棋Ai-权值法

    Java五子棋Ai-权值法 一. 什么是权值法? 二.实现权值法Ai会面临的问题 1.如何表达棋盘上未下处的横竖斜的棋子情况?(类似01120) 2.如何将未下处的横竖斜情况和权值联系起来?(Hash ...

  6. JAVA五子棋单机版

    Java五子棋设计流程: 1.创建窗口和设计一个棋盘界面 2.实现鼠标点击,棋子出现,黑白棋轮流下 3.能够判断输赢 4.添加按钮功能 4 实现结果图: import java.awt.BorderL ...

  7. 递归算法棋子移动java,java五子棋实习报告

    java五子棋实习报告 Java 程序设计基础 实习报告 课程名称 Java 程序设计基础 实习题目 java 五子棋 专 业 班 级 学 号 学生姓名 指导教师 Java 实习报告 一.一.J JA ...

  8. java五子棋游戏源代码_Java实现五子棋游戏的完整代码

    用Java编写简单的五子棋,供大家参考,具体内容如下 前言 这两天在空闲时间做了个五子棋项目,分享给大家看一下,界面是这样的: 界面很丑我知道,本人虽有几年PS基础,但知识浅薄,审美观不尽人意,做到如 ...

  9. java五子棋源代码文件,Java 网络版五子棋(含源代码)

    [实例简介] Java 五子棋 网络版 聊天 源代码 悔棋 认输 Swing [实例截图] [核心代码] Javaswing网络版五子棋 └── Java五子棋程序 ├── 11.jpg ├── 1. ...

  10. java五子棋难度_Java小项目之:五子棋,你下棋下得过电脑吗?

    Java小项目之:五子棋,你下棋下得过电脑吗? Java五子棋功能要求: 1.创建窗口和设计一个棋盘界面 2.实现鼠标点击,棋子出现,黑白棋轮流下 3.能够判断五子相连输赢 4.添加重新开始,悔棋,退 ...

最新文章

  1. zabbix数据库表结构简单解析
  2. 反射获取成员变量并改值
  3. RabbitMQ之监控(3)
  4. Angular Component 开发时属性和运行时属性的对照
  5. 使用prismjs为网站添加代码高亮功能
  6. android web canvas,HTML5 - Canvas无法在Android WebView的第一次加载时渲染
  7. jquery遍历元素对象each方法
  8. php redisson,排查redisson中订阅connection无故消失的问题
  9. 用百度人工智能进行繁体文字中文OCR识别
  10. Python调用海康威视网络摄像头进行远程人脸识别
  11. android viewholder静态,Android listview viewholder
  12. DJ Mix Pads 2 - Remix Version for Mac(独特DJ混音创作软件)
  13. 《金融学》笔记 第二章 货币制度
  14. 把方形头像切成圆形的头像工具类
  15. 喵星球上的点名——记一个用广义SAM根号维护多串的技巧
  16. 小学英语与计算机技术整合,小学英语课程与信息技术的整合
  17. 计算机专业就业率就业薪资图表,10大热门专业“工资”大揭秘,软件工程最高,会计垫底?...
  18. java学习常用网站推荐
  19. 简化开发: mybatis-plus 代码自动生成 以及 常见问题
  20. 略论错误提示的人性化

热门文章

  1. PLSql连接oracle64位
  2. android 手机左右移动图片轮播,js实现支持手机滑动切换的轮播图片效果实例
  3. 【Pytorch】AlexNet图像分类实战
  4. Excel竟然可以批量解锁二维码内容的操作
  5. 哪些产品需要做3C认证,费用是多少
  6. JAVA的三个版本,JSE,JEE,JME三者之间的区别
  7. 利用Python实现word文档合并
  8. 基于Java Web考生评分系统设计实现毕业设计源码071114
  9. 注册github一直显示验证码错误的问题
  10. 轻量级的layui框架后台模板