用Java编写简单的五子棋——人机对战!
前言
2022-02-04,农历正月初四
首先在这祝大家新年快乐。
距离上两个版本的更新已经过去了很久,因为年前工作非常忙,经常熬到凌晨,导致我看大家私信和回复的时间有限,但我会用上厕所摸鱼的宝贵时间仔细查看并回应大家的互动。
那天我看到有同学问我人机对战如何实现,说实话这玩意三言两语很难解释清楚,不如直接写一个让大家看来的直接,所以我没有回答他的问题,而是找时间把这个功能做出来,争取让所有想问这个问题的同学找到答案。
终于来到了年假,招待完亲戚朋友后,脑子里的第一件事就是将这个功能做完展示给大家,博主不才,花了一下午时间干出来,就当我给大家的新年礼物了。
测试类
import javax.swing.*;public class Test {public static void main(String[] args) {Object[] objects={"人人对战","人机对战"};int a = JOptionPane.showOptionDialog(null,"请选择游戏模式","请选择",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE,null, objects, objects[0]);System.out.println(a);if (a == 0){MyJFrame mj = new MyJFrame();mj.myJFrame();}else if (a == 1){MyJFrame_AI mjAI = new MyJFrame_AI();mjAI.myJFrame();}else{System.exit(0);}}
}
MyJFrame类代码
import jdk.nashorn.internal.scripts.JO;import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;public class MyJFrame extends JFrame implements MouseListener {int qx = 20, qy = 40, qw = 490, qh = 490; //棋盘位置、宽高int bw = 150, bh = 50, bx = 570, by = 150; //按钮宽高、位置int x = 0, y = 0; //保存棋子坐标int[][] SaveGame = new int[15][15]; //保存每个棋子int qc = 1;//记录白棋=2,黑棋=1int qn = 0;//判断棋子是否重复boolean canplay = true; //判断游戏是否开始和结束String go = "黑子先行"; //游戏信息int bq = 0, hq = 0;//---------------------------------------------------------------------------------------------------------------------//窗体public void myJFrame() {this.setTitle("五子棋"); //标题this.setSize(800, 550); //窗口大小this.setResizable(false); //窗口是否可以改变大小=否this.setDefaultCloseOperation(MyJFrame.EXIT_ON_CLOSE); //窗口关闭方式为关闭窗口同时结束程序int width = Toolkit.getDefaultToolkit().getScreenSize().width; //获取屏幕宽度int height = Toolkit.getDefaultToolkit().getScreenSize().height; //获取屏幕高度
// System.out.println("宽度:"+width);//测试
// System.out.println("高度:"+height);//测试this.setLocation((width - 800) / 2, (height - 600) / 2); //设置窗口默认位置以屏幕居中this.addMouseListener(this);this.setVisible(true); //窗口是否显示=是}public class Position {int listx;int listy;}public class chessUI extends JPanel {public Position[] ps = new Position[300];int i;}chessUI ui = new chessUI();Position p = new Position();//---------------------------------------------------------------------------------------------------------------------//覆写paint方法,绘制界面public void paint(Graphics g) {//双缓冲技术防止屏幕闪烁BufferedImage bi = new BufferedImage(800, 550, BufferedImage.TYPE_INT_ARGB);Graphics g2 = bi.createGraphics();//获取图片路径BufferedImage image = null;try {//获取项目文件夹路径File directory = new File("");//路径拼接image = ImageIO.read(new File(directory.getAbsolutePath() + "/tp/wzqbj.jpg"));} catch (IOException e) {e.printStackTrace();}g2.drawImage(image, 10, 10, this); //显示图片g2.setColor(Color.BLACK);//设置画笔颜色g2.setFont(new Font("华文行楷", 10, 50)); //设置字体g2.drawString("晓时五子棋", 525, 100); //绘制字符//棋盘g2.setColor(Color.getHSBColor(30, (float) 0.10, (float) 0.90)); //设置画笔颜色g2.fillRect(qx, qy, qw, qh); //绘制棋盘背景矩形//开始按钮g2.setColor(Color.WHITE); //设置画笔颜色g2.fillRect(bx, by, bw, bh); //绘制开始按钮g2.setFont(new Font("华文行楷", 10, 30)); //设置字体g2.setColor(Color.black); //设置画笔颜色g2.drawString("开始", 615, 185); //绘制字符//悔棋按钮g2.setColor(Color.LIGHT_GRAY); //设置画笔颜色g2.fillRect(bx, by + 60, bw, bh); //绘制悔棋按钮g2.setFont(new Font("华文行楷", 10, 30)); //设置字体g2.setColor(Color.WHITE); //设置画笔颜色 g2.drawString("悔棋", 615, 245); //绘制字符//认输按钮g2.setColor(Color.GRAY); //设置画笔颜色g2.fillRect(bx, by + 120, bw, bh); //绘制认输按钮g2.setFont(new Font("华文行楷", 10, 30)); //设置字体g2.setColor(Color.WHITE); //设置画笔颜色g2.drawString("认输", 615, 305); //绘制字符//游戏信息栏g2.setColor(Color.getHSBColor(30, (float) 0.10, (float) 0.90)); //设置画笔颜色g2.fillRect(550, 350, 200, 150); //绘制游戏状态区域g2.setColor(Color.black); //设置画笔颜色g2.setFont(new Font("黑体", 10, 20)); //设置字体g2.drawString("游戏信息", 610, 380); //绘制字符g2.drawString(go, 610, 410); //绘制字符g2.drawString("作者:晓时谷雨", 560, 440); //绘制字符g2.drawString("联系方式:", 560, 465); //绘制字符g2.drawString("qq 717535996", 560, 490); //绘制字符g2.setColor(Color.BLACK); //设置画笔颜色//绘制棋盘格线for (int x = 0; x <= qw; x += 35) {g2.drawLine(qx, x + qy, qw + qx, x + qy); //绘制一条横线g2.drawLine(x + qx, qy, x + qx, qh + qy); //绘制一条竖线}//绘制标注点for (int i = 3; i <= 11; i += 4) {for (int y = 3; y <= 11; y += 4) {g2.fillOval(35 * i + qx - 3, 35 * y + qy - 3, 6, 6); //绘制实心圆}}//绘制棋子for (int i = 0; i < 15; i++) {for (int j = 0; j < 15; j++) {if (SaveGame[i][j] == 1) //黑子{int sx = i * 35 + qx;int sy = j * 35 + qy;g2.setColor(Color.BLACK);g2.fillOval(sx - 13, sy - 13, 26, 26); //绘制实心圆hq++;}if (SaveGame[i][j] == 2) //白子{int sx = i * 35 + qx;int sy = j * 35 + qy;g2.setColor(Color.WHITE);g2.fillOval(sx - 13, sy - 13, 26, 26); //绘制实心圆g2.setColor(Color.BLACK);g2.drawOval(sx - 13, sy - 13, 26, 26); //绘制空心圆bq++;}}}g.drawImage(bi, 0, 0, this);// g.drawRect(20, 20, 20, 20);//绘制空心矩形}//---------------------------------------------------------------------------------------------------------------------//判断输赢private boolean WinLose() {boolean flag = false; //输赢int count = 1; //相连数int color = SaveGame[x][y]; //记录棋子颜色//判断横向棋子是否相连int i = 1; //迭代数while (color == SaveGame[x + i][y]) {count++;i++;}i = 1; //迭代数while (color == SaveGame[x - i][y]) {count++;i++;}if (count >= 5) {flag = true;}//判断纵向棋子是否相连count = 1;i = 1; //迭代数while (color == SaveGame[x][y + i]) {count++;i++;}i = 1; //迭代数while (color == SaveGame[x][y - i]) {count++;i++;}if (count >= 5) {flag = true;}//判断斜向棋子是否相连(左上右下)count = 1;i = 1; //迭代数while (color == SaveGame[x - i][y - i]) {count++;i++;}i = 1; //迭代数while (color == SaveGame[x + i][y + i]) {count++;i++;}if (count >= 5) {flag = true;}//判断斜向棋子是否相连(左下右上)count = 1;i = 1; //迭代数while (color == SaveGame[x + i][y - i]) {count++;i++;}i = 1; //迭代数while (color == SaveGame[x - i][y + i]) {count++;i++;}if (count >= 5) {flag = true;}return flag;}//---------------------------------------------------------------------------------------------------------------------//初始化游戏public void Initialize() {//遍历并初始化数组for (int i = 0; i < 15; i++) {for (int j = 0; j < 15; j++) {SaveGame[i][j] = 0;}}//黑子先行qc = 1;go = "轮到黑子";}//---------------------------------------------------------------------------------------------------------------------@Override //鼠标点击public void mouseClicked(MouseEvent e) {}@Override //鼠标按下public void mousePressed(MouseEvent e) {//判断是否已开始游戏if (canplay) {//获取鼠标点击位置x = e.getX();y = e.getY();ui.ps[ui.i] = p;//判断点击是否为棋盘内if (x > qx && x < qx + qw && y > qy && y < qy + qh) {//计算点击位置最近的点if ((x - qx) % 35 > 17) {x = (x - qx) / 35 + 1;} else {x = (x - qx) / 35;}if ((y - qy) % 35 > 17) {y = (y - qy) / 35 + 1;} else {y = (y - qy) / 35;}ui.ps[ui.i].listx = x;ui.ps[ui.i].listy = y;ui.i++;//判断当前位置有没有棋子if (SaveGame[x][y] == 0) {SaveGame[x][y] = qc;qn = 0;} else {qn = 1;}//切换棋子if (qn == 0) {if (qc == 1) {qc = 2;go = "轮到白子";} else {qc = 1;go = "轮到黑子";}}this.repaint(); //重新执行一次paint方法// 弹出胜利对话框boolean wl = this.WinLose();if (wl) {JOptionPane.showMessageDialog(this, "游戏结束," + (SaveGame[x][y] == 1 ? "黑方赢了" : "白方赢了")); //弹出提示对话框canplay = false;}//弹出平局对话框if (bq + hq == 255) {JOptionPane.showMessageDialog(this, "游戏结束,平局!"); //弹出提示对话框canplay = false;}// System.out.println(1); //测试} else {
// System.out.println(0); //测试}}//实现开始按钮//判断是否点击开始按钮if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by && e.getY() < by + bh) {//判断游戏是否开始if (!canplay) {//如果游戏结束,则开始游戏canplay = true;JOptionPane.showMessageDialog(this, "游戏开始");//初始化游戏Initialize();this.repaint(); //重新执行一次paint方法} else {//如果游戏进行中,则重新开始JOptionPane.showMessageDialog(this, "重新开始");//初始化游戏Initialize();this.repaint(); //重新执行一次paint方法}}//实现悔棋按钮//判断是否点击悔棋按钮if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by + 60 && e.getY() < by + 60 + bh) {//判断游戏是否开始if (canplay) {//遍历棋盘上是否有棋子int z = 0;for (int i = 0; i < 15; i++) {for (int j = 0; j < 15; j++) {if (SaveGame[i][j] != 0) {z++;}}}//判断是否有棋子if (z != 0) {int result = JOptionPane.showConfirmDialog(this, "确认要悔棋吗?");if (result == 0) {int x = ui.ps[ui.i - 1].listx;int y = ui.ps[ui.i - 1].listy;if (SaveGame[x][y] == 0){JOptionPane.showMessageDialog(this, "已悔过一次棋了!");}else{if (SaveGame[x][y] == 1) {qc = 1;go = "轮到黑子";} else if (SaveGame[x][y] == 2){qc = 2;go = "轮到白子";}SaveGame[x][y] = 0;ui.i--;this.repaint();}}} else {JOptionPane.showMessageDialog(this, "棋盘上已无棋子");}} else {JOptionPane.showMessageDialog(this, "请先开始游戏");}}//实现认输按钮//判断是否点击认输按钮if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by + 120 && e.getY() < by + 120 + bh) {//判断游戏是否开始if (canplay) {//判断是谁认输if (qc == 1) {JOptionPane.showMessageDialog(this, "黑方认输,白方获胜");canplay = false;} else if (qc == 2) {JOptionPane.showMessageDialog(this, "白方认输,黑方获胜");canplay = false;}} else {JOptionPane.showMessageDialog(this, "请先开始游戏");}}}@Override//鼠标抬起public void mouseReleased(MouseEvent e) {}@Override//鼠标进入public void mouseEntered(MouseEvent e) {}@Override//鼠标离开public void mouseExited(MouseEvent e) {}
}
MyJFrame_AI类代码
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;public class MyJFrame_AI extends JFrame implements MouseListener {int qx = 20, qy = 40, qw = 490, qh = 490; //棋盘位置、宽高int bw = 150, bh = 50, bx = 570, by = 150; //按钮宽高、位置int x = 0, y = 0; //保存棋子坐标int[][] SaveGame = new int[15][15]; //保存每个棋子int qc = 1;//记录白棋=2,黑棋=1int qn = 0;//判断棋子是否重复boolean canplay = true; //判断游戏是否开始和结束String go = "黑子先行"; //游戏信息int bq = 0, hq = 0;//人机对战增加参数int machine = 0;// 该数值为1代表电脑先行int[][] score = new int[15][15];// 权值表,保存每个位置的分数//---------------------------------------------------------------------------------------------------------------------//窗体public void myJFrame() {this.setTitle("五子棋(人机对战)"); //标题this.setSize(800, 550); //窗口大小this.setResizable(false); //窗口是否可以改变大小=否this.setDefaultCloseOperation(MyJFrame_AI.EXIT_ON_CLOSE); //窗口关闭方式为关闭窗口同时结束程序int width = Toolkit.getDefaultToolkit().getScreenSize().width; //获取屏幕宽度int height = Toolkit.getDefaultToolkit().getScreenSize().height; //获取屏幕高度
// System.out.println("宽度:"+width);//测试
// System.out.println("高度:"+height);//测试this.setLocation((width - 800) / 2, (height - 600) / 2); //设置窗口默认位置以屏幕居中this.addMouseListener(this);this.setVisible(true); //窗口是否显示=是first();}public static class Position {static int listx;static int listy;}public static class chessUI extends JPanel {public static Position[] ps = new Position[300];int i;}static chessUI ui = new chessUI();static Position p = new Position();//---------------------------------------------------------------------------------------------------------------------//覆写paint方法,绘制界面public void paint(Graphics g) {//双缓冲技术防止屏幕闪烁BufferedImage bi = new BufferedImage(800, 550, BufferedImage.TYPE_INT_ARGB);Graphics g2 = bi.createGraphics();//获取图片路径BufferedImage image = null;try {//获取项目文件夹路径File directory = new File("");//路径拼接image = ImageIO.read(new File(directory.getAbsolutePath() + "/tp/wzqbj.jpg"));} catch (IOException e) {e.printStackTrace();}g2.drawImage(image, 10, 10, this); //显示图片g2.setColor(Color.BLACK);//设置画笔颜色g2.setFont(new Font("华文行楷", 10, 50)); //设置字体g2.drawString("晓时五子棋", 525, 100); //绘制字符//棋盘g2.setColor(Color.getHSBColor(30, (float) 0.10, (float) 0.90)); //设置画笔颜色g2.fillRect(qx, qy, qw, qh); //绘制棋盘背景矩形//开始按钮g2.setColor(Color.WHITE); //设置画笔颜色g2.fillRect(bx, by, bw, bh); //绘制开始按钮g2.setFont(new Font("华文行楷", 10, 30)); //设置字体g2.setColor(Color.black); //设置画笔颜色g2.drawString("开始", 615, 185); //绘制字符//悔棋按钮g2.setColor(Color.LIGHT_GRAY); //设置画笔颜色g2.fillRect(bx, by + 60, bw, bh); //绘制悔棋按钮g2.setFont(new Font("华文行楷", 10, 30)); //设置字体g2.setColor(Color.WHITE); //设置画笔颜色 g2.drawString("悔棋", 615, 245); //绘制字符//认输按钮g2.setColor(Color.GRAY); //设置画笔颜色g2.fillRect(bx, by + 120, bw, bh); //绘制认输按钮g2.setFont(new Font("华文行楷", 10, 30)); //设置字体g2.setColor(Color.WHITE); //设置画笔颜色g2.drawString("认输", 615, 305); //绘制字符//游戏信息栏g2.setColor(Color.getHSBColor(30, (float) 0.10, (float) 0.90)); //设置画笔颜色g2.fillRect(550, 350, 200, 150); //绘制游戏状态区域g2.setColor(Color.black); //设置画笔颜色g2.setFont(new Font("黑体", 10, 20)); //设置字体g2.drawString("游戏信息", 610, 380); //绘制字符g2.drawString(go, 610, 410); //绘制字符g2.drawString("作者:晓时谷雨", 560, 440); //绘制字符g2.drawString("联系方式:", 560, 465); //绘制字符g2.drawString("qq 717535996", 560, 490); //绘制字符g2.setColor(Color.BLACK); //设置画笔颜色//绘制棋盘格线for (int x = 0; x <= qw; x += 35) {g2.drawLine(qx, x + qy, qw + qx, x + qy); //绘制一条横线g2.drawLine(x + qx, qy, x + qx, qh + qy); //绘制一条竖线}//绘制标注点for (int i = 3; i <= 11; i += 4) {for (int y = 3; y <= 11; y += 4) {g2.fillOval(35 * i + qx - 3, 35 * y + qy - 3, 6, 6); //绘制实心圆}}//绘制棋子for (int i = 0; i < 15; i++) {for (int j = 0; j < 15; j++) {if (SaveGame[i][j] == 1) //黑子{int sx = i * 35 + qx;int sy = j * 35 + qy;g2.setColor(Color.BLACK);g2.fillOval(sx - 13, sy - 13, 26, 26); //绘制实心圆hq++;}if (SaveGame[i][j] == 2) //白子{int sx = i * 35 + qx;int sy = j * 35 + qy;g2.setColor(Color.WHITE);g2.fillOval(sx - 13, sy - 13, 26, 26); //绘制实心圆g2.setColor(Color.BLACK);g2.drawOval(sx - 13, sy - 13, 26, 26); //绘制空心圆bq++;}}}g.drawImage(bi, 0, 0, this);// g.drawRect(20, 20, 20, 20);//绘制空心矩形}//---------------------------------------------------------------------------------------------------------------------//判断输赢private boolean WinLose() {boolean flag = false; //输赢int count = 1; //相连数int color = SaveGame[x][y]; //记录棋子颜色//判断横向棋子是否相连int i = 1; //迭代数while (color == SaveGame[x + i][y]) {count++;i++;}i = 1; //迭代数while (color == SaveGame[x - i][y]) {count++;i++;}if (count >= 5) {flag = true;}//判断纵向棋子是否相连count = 1;i = 1; //迭代数while (color == SaveGame[x][y + i]) {count++;i++;}i = 1; //迭代数if (y > 0) {while (color == SaveGame[x][y - i]) {count++;i++;}}if (count >= 5) {flag = true;}//判断斜向棋子是否相连(左上右下)count = 1;i = 1; //迭代数while (color == SaveGame[x - i][y - i]) {count++;i++;}i = 1; //迭代数while (color == SaveGame[x + i][y + i]) {count++;i++;}if (count >= 5) {flag = true;}//判断斜向棋子是否相连(左下右上)count = 1;i = 1; //迭代数while (color == SaveGame[x + i][y - i]) {count++;i++;}i = 1; //迭代数while (color == SaveGame[x - i][y + i]) {count++;i++;}if (count >= 5) {flag = true;}return flag;}//---------------------------------------------------------------------------------------------------------------------//初始化游戏public void Initialize() {//遍历并初始化棋子位置数组for (int i = 0; i < 15; i++) {for (int j = 0; j < 15; j++) {SaveGame[i][j] = 0;}}//遍历并初始化权值数组for (int i = 0; i < 15; i++) {for (int j = 0; j < 15; j++) {score[i][j] = 0;}}//黑子先行qc = 1;go = "轮到黑子";first();}/*** 判断谁先走*/public void first() {Object[] objects = {"玩家先走", "电脑先走"};int a = JOptionPane.showOptionDialog(null, "请选择先行者", "请选择", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, objects, objects[0]);if (a == -1) {System.exit(0);}if (a == 1) {machine = 1;}if (a == 0) {machine = 0;}// 如果电脑先走,在中间位置下棋if (machine == 1) {SaveGame[7][7] = 1;qc = 2;go = "轮到白子";this.repaint();}}/*** 计算五元组分数*/public int score(int blackNum, int whiteNum) {// 通过电脑是否先行判断电脑棋子颜色// 如果电脑执黑if (machine == 1) {// 如果五元组中两种棋子都有,分值为0if (blackNum > 0 && whiteNum > 0) {return 0;}// 都没有,分值为7if (blackNum == 0 && whiteNum == 0) {return 7;}// 判断其中白棋数量计算分数if (blackNum == 1) {return 35;}if (blackNum == 2) {return 800;}if (blackNum == 3) {return 15000;}if (blackNum == 4) {return 800000;}// 判断其中白棋数量计算分数if (whiteNum == 1) {return 15;}if (whiteNum == 2) {return 400;}if (whiteNum == 3) {return 1800;}if (whiteNum == 4) {return 100000;}// 如果改五元组白棋数量为0
// if (whiteNum == 0) {
// // 判断其中黑棋数量计算分数
// if (blackNum == 0) {
// score = 7;
// }
// if (blackNum == 1) {
// score = 35;
// }
// if (blackNum == 2) {
// score = 800;
// }
// if (blackNum == 3) {
// score = 15000;
// }
// if (blackNum == 4) {
// score = 800000;
// }
// }
// // 如果改五元组黑棋数量为0
// if (blackNum == 0) {
// // 判断其中白棋数量计算分数
// if (whiteNum == 0) {
// score = 7;
// }
// if (whiteNum == 1) {
// score = 15;
// }
// if (whiteNum == 2) {
// score = 400;
// }
// if (whiteNum == 3) {
// score = 1800;
// }
// if (whiteNum == 4) {
// score = 100000;
// }
// }}// 如果电脑执白if (machine == 0) {// 如果五元组中两种棋子都有,分值为0if (blackNum > 0 && whiteNum > 0) {return 0;}// 都没有,分值为7if (blackNum == 0 && whiteNum == 0) {return 7;}// 判断其中白棋数量计算分数if (blackNum == 1) {return 15;}if (blackNum == 2) {return 400;}if (blackNum == 3) {return 1800;}if (blackNum == 4) {return 100000;}// 判断其中白棋数量计算分数if (whiteNum == 1) {return 35;}if (whiteNum == 2) {return 800;}if (whiteNum == 3) {return 15000;}if (whiteNum == 4) {return 800000;}
// // 如果改五元组白棋数量为0
// if (whiteNum == 0) {
// // 判断其中黑棋数量计算分数
// if (blackNum == 0) {
// score = 7;
// }
// if (blackNum == 1) {
// score = 15;
// }
// if (blackNum == 2) {
// score = 400;
// }
// if (blackNum == 3) {
// score = 1800;
// }
// if (blackNum == 4) {
// score = 100000;
// }
// }
// // 如果改五元组黑棋数量为0
// if (blackNum == 0) {
// // 判断其中白棋数量计算分数
// if (whiteNum == 0) {
// score = 7;
// }
// if (whiteNum == 1) {
// score = 35;
// }
// if (whiteNum == 2) {
// score = 800;
// }
// if (whiteNum == 3) {
// score = 15000;
// }
// if (whiteNum == 4) {
// score = 800000;
// }
// }}return -1;}/*** 判断人机最佳下棋位置*/public void machineGo(int pieces) {int blackNum = 0;int whiteNum = 0;// 横向for (int i = 0; i < 15; i++) {for (int j = 0; j < 11; j++) {int k = j;while (k < j + 5) {if (SaveGame[i][k] == 1) {blackNum++;} else if (SaveGame[i][k] == 2) {whiteNum++;}k++;}// 给五元组每个没有落子的位置添加分数for (k = j; k < j + 5; k++) {if (score[i][k] == 0) {score[i][k] += score(blackNum, whiteNum);}}// 将上次值归零,以便下次计算blackNum = 0;whiteNum = 0;}}// 纵向for (int i = 0; i < 15; i++) {for (int j = 0; j < 11; j++) {int k = j;while (k < j + 5) {if (SaveGame[k][i] == 1) {blackNum++;} else if (SaveGame[k][i] == 2) {whiteNum++;}k++;}// 给五元组每个没有落子的位置添加分数for (k = j; k < j + 5; k++) {score[k][i] += score(blackNum, whiteNum);}// 将上次值归零,以便下次计算blackNum = 0;whiteNum = 0;}}//右上左下,上部分for (int i = 14; i >= 4; i--) {for (int k = i, j = 0; j < 15 && k >= 0; j++, k--) {int m = k;int n = j;while (m > k - 5 && k - 5 >= -1) {if (SaveGame[m][n] == 1) {blackNum++;} else if (SaveGame[m][n] == 2) {whiteNum++;}m--;n++;}// 斜向判断时,可能无法构成五元组,进行判断对其忽略if (m == k - 5) {for (m = k, n = j; m > k - 5; m--, n++) {score[m][n] += score(blackNum, whiteNum);}}// 将上次值归零,以便下次计算blackNum = 0;whiteNum = 0;}}//右上左下,下部分for (int i = 1; i < 15; i++) {for (int k = i, j = 14; j >= 0 && k < 15; j--, k++) {int m = k;int n = j;while (m < k + 5 && k + 5 <= 15) {if (SaveGame[n][m] == 1) {blackNum++;} else if (SaveGame[n][m] == 2) {whiteNum++;}m++;n--;}// 斜向判断时,可能无法构成五元组,进行判断对其忽略if (m == k + 5) {for (m = k, n = j; m < k + 5; m++, n--) {score[n][m] += score(blackNum, whiteNum);}}// 将上次值归零,以便下次计算blackNum = 0;whiteNum = 0;}}// 左上右下,上部分for (int i = 0; i < 11; i++) {for (int k = i, j = 0; j < 15 && k < 15; j++, k++) {int m = k;int n = j;while (m < k + 5 && k + 5 <= 15) {if (SaveGame[m][n] == 1) {blackNum++;} else if (SaveGame[m][n] == 2) {whiteNum++;}m++;n++;}// 斜向判断时,可能无法构成五元组,进行判断对其忽略if (m == k + 5) {//为该五元组的每个位置添加分数for (m = k, n = j; m < k + 5; m++, n++) {score[m][n] += score(blackNum, whiteNum);}}// 将上次值归零,以便下次计算blackNum = 0;whiteNum = 0;}}// 左上右下,下部分for (int i = 1; i < 11; i++) {for (int k = i, j = 0; j < 15 && k < 15; j++, k++) {int m = k;int n = j;while (m < k + 5 && k + 5 <= 15) {if (SaveGame[n][m] == 1) {blackNum++;} else if (SaveGame[n][m] == 2) {whiteNum++;}m++;n++;}// 斜向判断时,可能无法构成五元组,进行判断对其忽略if (m == k + 5) {//为该五元组的每个位置添加分数for (m = k, n = j; m < k + 5; m++, n++) {score[n][m] += score(blackNum, whiteNum);}}// 将上次值归零,以便下次计算blackNum = 0;whiteNum = 0;}}int maxScore = 0;// 从没有落子的位置,找到分数最大的for (int i = 0; i < 15; i++) {for (int j = 0; j < 15; j++) {if (SaveGame[i][j] == 0 && score[i][j] > maxScore) {x = i;y = j;maxScore = score[i][j];}}}SaveGame[x][y] = pieces;ui.ps[ui.i].listx = x;ui.ps[ui.i].listy = y;ui.i++;this.repaint(); //重新执行一次paint方法// 弹出胜利对话框boolean wl = this.WinLose();if (wl) {JOptionPane.showMessageDialog(this, "游戏结束," + (SaveGame[x][y] == 1 ? "黑方赢了" : "白方赢了")); //弹出提示对话框canplay = false;}//弹出平局对话框if (bq + hq == 255) {JOptionPane.showMessageDialog(this, "游戏结束,平局!"); //弹出提示对话框canplay = false;}}//---------------------------------------------------------------------------------------------------------------------@Override //鼠标点击public void mouseClicked(MouseEvent e) {}@Override //鼠标按下public void mousePressed(MouseEvent e) {//判断是否已开始游戏if (canplay) {//获取鼠标点击位置x = e.getX();y = e.getY();ui.ps[ui.i] = p;//判断点击是否为棋盘内if (x > qx && x < qx + qw && y > qy && y < qy + qh) {//计算点击位置最近的点if ((x - qx) % 35 > 17) {x = (x - qx) / 35 + 1;} else {x = (x - qx) / 35;}if ((y - qy) % 35 > 17) {y = (y - qy) / 35 + 1;} else {y = (y - qy) / 35;}ui.ps[ui.i].listx = x;ui.ps[ui.i].listy = y;ui.i++;//判断当前位置有没有棋子if (SaveGame[x][y] == 0) {SaveGame[x][y] = qc;qn = 0;} else {qn = 1;}//切换棋子if (qn == 0) {if (qc == 1) {qc = 2;go = "轮到白子";} else {qc = 1;go = "轮到黑子";}}this.repaint(); //重新执行一次paint方法// 弹出胜利对话框boolean wl = this.WinLose();if (wl) {JOptionPane.showMessageDialog(this, "游戏结束," + (SaveGame[x][y] == 1 ? "黑方赢了" : "白方赢了")); //弹出提示对话框canplay = false;}//弹出平局对话框if (bq + hq == 255) {JOptionPane.showMessageDialog(this, "游戏结束,平局!"); //弹出提示对话框canplay = false;}// System.out.println(1); //测试}}//实现开始按钮//判断是否点击开始按钮if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by && e.getY() < by + bh) {//判断游戏是否开始if (!canplay) {//如果游戏结束,则开始游戏canplay = true;JOptionPane.showMessageDialog(this, "游戏开始");//初始化游戏Initialize();this.repaint(); //重新执行一次paint方法} else {//如果游戏进行中,则重新开始JOptionPane.showMessageDialog(this, "重新开始");//初始化游戏Initialize();this.repaint(); //重新执行一次paint方法}}//实现悔棋按钮//判断是否点击悔棋按钮if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by + 60 && e.getY() < by + 60 + bh) {//判断游戏是否开始if (canplay) {//遍历棋盘上是否有棋子int z = 0;for (int i = 0; i < 15; i++) {for (int j = 0; j < 15; j++) {if (SaveGame[i][j] != 0) {z++;}}}//判断是否有棋子if (z != 0) {int result = JOptionPane.showConfirmDialog(this, "确认要悔棋吗?");if (result == 0) {int x = ui.ps[ui.i - 1].listx;int y = ui.ps[ui.i - 1].listy;if (SaveGame[x][y] == 0) {JOptionPane.showMessageDialog(this, "已悔过一次棋了!");} else {if (SaveGame[x][y] == 1) {qc = 1;go = "轮到黑子";} else if (SaveGame[x][y] == 2) {qc = 2;go = "轮到白子";}SaveGame[x][y] = 0;ui.i--;this.repaint();}}} else {JOptionPane.showMessageDialog(this, "棋盘上已无棋子");}} else {JOptionPane.showMessageDialog(this, "请先开始游戏");}}//实现认输按钮//判断是否点击认输按钮if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by + 120 && e.getY() < by + 120 + bh) {//判断游戏是否开始if (canplay) {//判断是谁认输if (qc == 1) {JOptionPane.showMessageDialog(this, "黑方认输,白方获胜");canplay = false;} else if (qc == 2) {JOptionPane.showMessageDialog(this, "白方认输,黑方获胜");canplay = false;}} else {JOptionPane.showMessageDialog(this, "请先开始游戏");}}}@Override//鼠标抬起public void mouseReleased(MouseEvent e) {//如果电脑先行,就也代表电脑执黑子,否则反之。在相应回合时让电脑做出反应if (machine == 1) {if (qc == 1) {machineGo(qc);qc = 2;go = "轮到白子";}} else {if (qc == 2) {machineGo(qc);qc = 1;go = "轮到黑子";}}}@Override//鼠标进入public void mouseEntered(MouseEvent e) {}@Override//鼠标离开public void mouseExited(MouseEvent e) {}
}
结束语
原来的MyJFrame类里的代码没有改变,依然是人人对战;MyJFrame_AI类是在MyJFrame类的基础上修改为人机对战。
博主测试的比较匆忙,只玩了一遍,没有发现BUG,大家在游玩过程中如果发现BUG,欢迎私信。
往期文章可以翻阅我的主页,我一直坚持“分享知识”的原则,免费透明的将全部代码公开展示,如果帮到了你,请顺手点个赞吧(#.#)。
更新
2022-02-04
不放心,又测试了一晚上BUG,果然有问题:
1.修复了悔棋时只能撤回电脑棋子的BUG
2.修复了在特定情况下,电脑方或玩家方胜利没有反应的BUG
3.优化了电脑的权值计算,但还是不太聪明的样子