java基础软件开发app之五子棋
Posted 醉画仙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java基础软件开发app之五子棋相关的知识,希望对你有一定的参考价值。
五子棋人机对战实践项目
总的任务和目标
完成一个人机对战的五子棋项目,基本效果如下:
第一部分 Java绘图原理
1. 基本概念
像素,坐标
第二部分 绘制棋盘
1. 基本思路
在一个JPanel上绘制一个背景,然后绘制水平和垂直的若干条线,使其构成等距离的格子,通常是15*15(条线)。
2. 代码实现
第三部分 绘制棋子
1. 基本思路
使用drawOval()可以绘制空心的圆,使用fillOval()可以填充实心的圆。
2. 坐标计算
由于格子是水平和垂直的有下标的,而绘制时需要使用实际的像素坐标,所以,需要进行行列下标到像素坐标的转换:
int x = col * GRID_WIDTH;
int y = row * GRID_WIDTH;
3. 代码实现
(1) ChessPanel代码:
第四部分 鼠标下棋
1. 基本思路
需要处理鼠标单点事件,获取鼠标所在的位置,然后计算出应该绘制棋子的行列下标,并使用一个二维数组来全局存储棋子的位置。
2. 鼠标位置与行列下标计算
int x = e.getX();
int y = e.getY();
int row = y / GRID_WIDTH;
int col = x / GRID_WIDTH;
3. 代码实现
(1) ChessPanel属性和构造方法代码:
(2)监听器类(内部类)代码:
(3)绘图代码:
第五部分 判断胜负
1. 基本思路
判断胜负是因为在当前位置(row, col)落子导致了胜负,所以,判断胜负其实是在当前落子位置为中心,横向搜索左边第4个位置开始到右边第4个位置(其余位置不需要考虑),或者从上到下,或者正向45度,或者反向45度位置。
2. 处理方法
处理方法有很多,可以采用计数的方式,也可以采用字符串连接的方式,此处采用了将从左边第4颗开始,到右边第4颗结束,将每颗的颜色表示成字符1(黑色)或者2(白色),只需要判断其中是否有连续的5个1或5个2,即“11111”或“22222”即可知道胜负。
3. 代码实现
(1) 监听器类(内部类)代码:
(2)checkWin判断胜负的代码:
/** 判断胜负
* @param row 落子的行下标
* @param col 落子的列下标
* @return 是否获胜,true-是,false-否
*/
public boolean checkWin(int row, int col) {}
(3)重置游戏状态
【目前代码】
1 package wuziqi; 2 3 import java.awt.Color; 4 import java.awt.Container; 5 import java.awt.Graphics; 6 import java.awt.event.MouseAdapter; 7 import java.awt.event.MouseEvent; 8 9 import javax.swing.JFrame; 10 import javax.swing.JOptionPane; 11 import javax.swing.JPanel; 12 13 public class wuziqijiemianDemo { 14 //创建窗口为主类的类部类并且继承自JFrame 15 public class Myjframe extends JFrame { 16 /** 17 * 用一个构造方法创建窗口 18 */ 19 public Myjframe() { 20 this.setTitle("五子棋"); 21 this.setSize(620, 640); 22 //获取内容面板 23 Container cp = getContentPane(); 24 //创建一个面板JPanel 25 JPanel jPanel = new MyJanel(); 26 cp.add(jPanel); 27 //面板的背景颜色为黄色,便于下白棋与黑棋 28 jPanel.setBackground(Color.yellow); 29 this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); 30 //窗口默认设置为显示屏的正中间 31 this.setLocationRelativeTo(null); 32 //不可改变窗口的大小 33 this.setResizable(false); 34 } 35 } 36 /** 37 * 创建一个面板继承自JPanel 38 * @author Administrator 39 * 40 */ 41 public class MyJanel extends JPanel { 42 //表示每个方格的大小 43 private static final int GRID_WIDTh = 40; 44 //棋盘的大小,代表棋盘的线的条数 45 private static final int LINE_COUNT = 15; 46 //设置黑棋子为1、白棋子为2、没有棋子为0(默认值) 47 public static final int BLACK=1; 48 public static final int WHITE=2; 49 //定义一个棋盘大小的数组用来存放黑棋和白棋的位置 50 int[][] chessItems=new int[LINE_COUNT][LINE_COUNT]; 51 //定义一个标志位,代表黑棋先下(黑棋和白棋轮流下棋) 52 int flag=BLACK; 53 /** 54 * 构造方法用来画棋盘的棋子 55 */ 56 public MyJanel(){ 57 /** 58 * 为这个面板添加一个鼠标点击事件,鼠标每点击一次,就在棋盘上下一个棋子 59 *使用适配器的方式添加鼠标点击事件 60 */ 61 this.addMouseListener(new MouseAdapter() { 62 public void mouseClicked(MouseEvent e){ 63 /** 64 * 获取当前的鼠标点击的位置 65 */ 66 int x=e.getX(); 67 int y=e.getY(); 68 /** 69 * 因为棋盘是用二维数组的方式表示的,所以最后表示为二维数组的行与列 70 */ 71 int row=y/GRID_WIDTh; 72 int col=x/GRID_WIDTh; 73 //当前这个位置没有棋子(为零),可以下一个黑棋子 74 if(chessItems[row][col]==0){ 75 if(flag==BLACK){ 76 chessItems[row][col]=flag; 77 //下完黑棋下白棋 78 flag=WHITE; 79 //必须有,不然后面的白棋会覆盖黑棋 80 } 81 //当前这个位置没有棋子(为零),可以下一个白棋子 82 else{ 83 chessItems[row][col]=flag; 84 //下完白棋下黑棋 85 flag=BLACK; 86 } 87 } 88 /** 89 * 每当下完一步棋之后便判断是否已经取胜 90 */ 91 if(checkImage(row,col)){ 92 //显示对话窗口 93 JOptionPane.showMessageDialog(null, "your win"); 94 //清空棋盘 95 clear(); 96 } 97 //System.out.println(chessItems[row][col]); 98 } 99 }); 100 } 101 /** 102 * 调用public void paintComponent(Graphics arg0){};方法画图 103 */ 104 public void paintComponent(Graphics g) { 105 //系统调用 106 super.paintComponent(g); 107 // g.setColor(Color.yellow); 108 // g.fillRect(0, 0, jPanel.width(),jPanel.height()); 109 /** 110 * 画横线,起始位置在窗口左上定点(GRID_WIDTh/2,GRID_WIDTh/2) 111 */ 112 for (int i = 0; i < LINE_COUNT; i++) { 113 int x1 = GRID_WIDTh / 2; 114 int y1 = GRID_WIDTh / 2 + i * GRID_WIDTh; 115 int x2 = x1 + (LINE_COUNT-1)* GRID_WIDTh; 116 int y2 = y1; 117 //画线 118 g.drawLine(x1, y1, x2, y2); 119 } 120 /** 121 * 画竖线 122 */ 123 for (int i = 0; i < LINE_COUNT; i++) { 124 int x1 = GRID_WIDTh / 2 + i * GRID_WIDTh; 125 int y1 = GRID_WIDTh / 2; 126 int x2 = x1; 127 int y2 = y1 + (LINE_COUNT-1) * GRID_WIDTh; 128 //画线 129 g.drawLine(x1, y1, x2, y2); 130 } 131 /** 132 * 遍历这个数组 133 */ 134 for(int row=0;row<LINE_COUNT;row++){ 135 for(int col=0;col<LINE_COUNT;col++){ 136 //判断数组当前值,来画棋子 137 switch (chessItems[row][col]) { 138 case WHITE:chessItem(row, col, Color.WHITE, g);break; 139 case BLACK:chessItem(row, col, Color.BLACK, g);break; 140 } 141 repaint(); 142 } 143 } 144 }; 145 /** 146 * 清空数组,便于下次下棋 147 */ 148 private void clear() { 149 for(int row=0;row<LINE_COUNT;row++){ 150 for(int col=0;col<LINE_COUNT;col++){ 151 //全部置为0 152 chessItems[row][col]=0; 153 } 154 } 155 //重画一遍棋盘 156 repaint(); 157 } 158 /** 159 * 用于判断是否已经取胜 160 * @param row 161 * @param col 162 * @return 163 */ 164 private boolean checkImage(int row, int col) { 165 /** 166 * 判断横行是否win 167 */ 168 StringBuilder stringBuilder=new StringBuilder(); 169 //记录当前存在字符串中的数据个数 170 int count=0; 171 for(int i=-4;i<=4;i++){ 172 int Newcol=col+i; 173 if(Newcol>=0&&Newcol<LINE_COUNT){ 174 count++; 175 stringBuilder.append(chessItems[row][Newcol]); 176 } 177 } 178 if(stringBuilder.indexOf("11111")>=0||stringBuilder.indexOf("22222")>=0){ 179 return true; 180 }else { 181 //如果当前不能赢,则清空字符串 182 stringBuilder.delete(0, count); 183 count=0; 184 } 185 /** 186 * 判断竖行是否win 187 */ 188 for(int i=-4;i<=4;i++){ 189 int Newrow=row+i; 190 if(Newrow>=0&&Newrow<LINE_COUNT){ 191 count++; 192 stringBuilder.append(chessItems[Newrow][col]); 193 } 194 } 195 if(stringBuilder.indexOf("11111")>=0||stringBuilder.indexOf("22222")>=0){ 196 return true; 197 }else { 198 stringBuilder.delete(0, count); 199 count=0; 200 } 201 /** 202 * 判断负45°是否win 203 */ 204 for(int i=-4;i<=4;i++){ 205 int Newcol=col+i; 206 int Newrow=row+i; 207 if(Newcol>=0&&Newcol<LINE_COUNT&&Newrow>=0&&Newrow<LINE_COUNT){ 208 count++; 209 stringBuilder.append(chessItems[Newrow][Newcol]); 210 } 211 } 212 if(stringBuilder.indexOf("11111")>=0||stringBuilder.indexOf("22222")>=0){ 213 return true; 214 }else { 215 stringBuilder.delete(0, count); 216 count=0; 217 } 218 /** 219 * 判断正45°是否win 220 */ 221 for(int i=-4;i<=4;i++){ 222 int Newcol=col+i; 223 int Newrow=row-i; 224 if(Newcol>=0&&Newcol<LINE_COUNT&&Newrow>=0&&Newrow<LINE_COUNT){ 225 count++; 226 stringBuilder.append(chessItems[Newrow][Newcol]); 227 } 228 } 229 if(stringBuilder.indexOf("11111")>=0||stringBuilder.indexOf("22222")>=0){ 230 return true; 231 }else { 232 stringBuilder.delete(0, count); 233 count=0; 234 } 235 return false; 236 } 237 //画棋子 238 public void chessItem(int row,int col,Color color,Graphics graphics){ 239 //x与y分别代表在面板上的位置 240 int x=col*GRID_WIDTh; 241 int y=row*GRID_WIDTh; 242 graphics.setColor(color); 243 //画圆 244 graphics.fillOval(x, y, GRID_WIDTh,GRID_WIDTh); 245 } 246 } 247 248 public static void main(String[] args) { 249 /** 250 * 使用一个java类来创建一个主类为wuziqijiemianDemo,其中的窗口与棋盘为该主类的内部类 251 */ 252 //使用类部类的方式创建一个窗口引用对象(方式为 外部类名.内部类名 变量名=new 外部类名().new 内部类名();) 253 wuziqijiemianDemo.Myjframe myjframe = new wuziqijiemianDemo().new Myjframe(); 254 //设置窗口可见 255 myjframe.setVisible(true); 256 } 257 258 }
第六部分 人机对战
1. 基本思路
当人点了鼠标落子以后,轮到电脑下棋,电脑的基本思想就是,在棋盘的空白处的每个位置,进行判断,当前位置的进攻指数和防守指数分别为多少,在进攻指数和防守指数中取一个较大值作为当前位置的评估值,在整个棋盘的所有空白处找到一个最大值,最大值的那个位置即为应该落子的位置。
2. 代码实现
(1)监听器类(内部类)代码:
(2)电脑下棋的代码
(3) 评估关键参数代码:
(4) 评估方法代码:
【自己代码】
1 package wuziqi; 2 3 import java.awt.Color; 4 import java.awt.Container; 5 import java.awt.Graphics; 6 import java.awt.Image; 7 import java.awt.Point; 8 import java.awt.event.MouseAdapter; 9 import java.awt.event.MouseEvent; 10 import java.io.File; 11 import java.io.IOException; 12 13 import javax.imageio.ImageIO; 14 import javax.swing.JFrame; 15 import javax.swing.JOptionPane; 16 import javax.swing.JPanel; 17 18 public class wuziqijiemianDemo { 19 // 创建窗口为主类的类部类并且继承自JFrame 20 public class Myjframe extends JFrame { 21 /** 22 * 用一个构造方法创建窗口 23 */ 24 public Myjframe() { 25 this.setTitle("五子棋"); 26 this.setSize(620, 640); 27 // 获取内容面板 28 Container cp = getContentPane(); 29 // 创建一个面板JPanel 30 JPanel jPanel = new MyJanel(); 31 cp.add(jPanel); 32 // 面板的背景颜色为黄色,便于下白棋与黑棋 33 jPanel.setBackground(Color.yellow); 34 this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); 35 // 窗口默认设置为显示屏的正中间 36 this.setLocationRelativeTo(null); 37 // 不可改变窗口的大小 38 this.setResizable(false); 39 } 40 } 41 42 /** 43 * 创建一个面板继承自JPanel 44 * 45 * @author Administrator 46 * 47 */ 48 public class MyJanel extends JPanel { 49 // 表示每个方格的大小 50 private static final int GRID_WIDTh = 40; 51 // 棋盘的大小,代表棋盘的线的条数 52 private static final int LINE_COUNT = 15; 53 // 设置黑棋子为1、白棋子为2、没有棋子为0(默认值) 54 public static final int BLACK = 1; 55 public static final int WHITE = 2; 56 // 定义一个棋盘大小的数组用来存放黑棋和白棋的位置 57 int[][] chessItems = new int[LINE_COUNT][LINE_COUNT]; 58 // 定义一个标志位,代表黑棋先下(黑棋和白棋轮流下棋) 59 int flag = BLACK; 60 //定义一个方框标记计算机下棋的棋子 61 private Point lastpoint=new Point(); 62 //利用图片代表棋子 63 Image blackImage=null; 64 Image whiImage=null; 65 //定义一个进攻的数组 66 String[] defendstring={ 67 "11111","011110","11110","01111","11011", 68 "10111","11101","01110","11100","00111", 69 "0111","1110","1011","1101","111", 70 "01100","00110","011","110","11" 71 }; 72 //定义一个防守的数组 73 String[] attackstring={ 74 "22222","022220","22220","02222","22022", 75 "20222","22202","02220","22200","00222", 76 "0222","2220","2022","2202","222", 77 "02200","00220","022","220","22" 78 }; 79 //定义一个防守与进攻对应的得分 80 int[] score={ 81 100,90,80,80,80, 82 80,80,70,60,60, 83 50,50,50,50,40, 84 30,30,20,20,10, 85 }; 86 /** 87 * 构造方法用来画棋盘的棋子 88以上是关于java基础软件开发app之五子棋的主要内容,如果未能解决你的问题,请参考以下文章