五子棋人机对战实践项目

总的任务和目标

完成一个人机对战的五子棋项目,基本效果如下:

第一部分 Java绘图原理

1.   基本概念

像素,坐标

2.   组件自定义绘图原理

3.   Graphics对象的常用方法

setFont(), setColor(), drawLine(), drawString(), drawOval(), drawRect(), fillOval(), fillRect(), drawImage()

第二部分 绘制棋盘

1.   基本思路

在一个JPanel上绘制一个背景,然后绘制水平和垂直的若干条线,使其构成等距离的格子,通常是15*15(条线)。

2.   代码实现

(1)主类代码:

(2) ChessPanel代码:

第三部分 绘制棋子

1.   基本思路

使用drawOval()可以绘制空心的圆,使用fillOval()可以填充实心的圆。

2.   坐标计算

由于格子是水平和垂直的有下标的,而绘制时需要使用实际的像素坐标,所以,需要进行行列下标到像素坐标的转换:

int x = col * GRID_WIDTH;

int y = row * GRID_WIDTH;

3.   代码实现

第四部分 鼠标下棋

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判断胜负的代码:

/**判断胜负

*@paramrow 落子的行下标

*@paramcol 落子的列下标

*@return是否获胜,true-是,false-否*/

public boolean checkWin(int row, intcol) {}

(3)重置游戏状态

第六部分 人机对战

1.   基本思路

当人点了鼠标落子以后,轮到电脑下棋,电脑的基本思想就是,在棋盘的空白处的每个位置,进行判断,当前位置的进攻指数和防守指数分别为多少,在进攻指数和防守指数中取一个较大值作为当前位置的评估值,在整个棋盘的所有空白处找到一个最大值,最大值的那个位置即为应该落子的位置。

2.   某个位置的进攻指数和防守指数的评估方法

本例中简化此问题,依据第五部分中胜负判断的方式,对连续9个位置形成的字符串进行搜索、评分,得出一个评估方案。如“11111”代表连续5个黑色,评分100,“011110”代表连续4个黑色,两端为空位置,评分90……。

3.   代码实现

(1)监听器类(内部类)代码:

(2)     电脑下棋的代码:

(3)     评估关键参数代码:

(4) 评估方法代码:

以上为本次人机对战的实践项目要求及部分实现代码,下面展示自己的完整代码(有所改变):

【主类DrawFrame】

1 packageqipan;2

3 importjava.awt.BorderLayout;4 importjava.awt.Container;5 import java.awt.*;6 importjavax.swing.JFrame;7

8 public class DrawFrame extendsJFrame{9 //属性

10 Mypanel panel=null;11

12 //方法

13 publicDrawFrame(){14 //设置主面板

15 setTitle("五子棋");16 setSize(620,640);17 setDefaultCloseOperation(DISPOSE_ON_CLOSE);18 setLocationRelativeTo(null);19 setResizable(false);20

21 //设置绘图面板

22 Container cp =getContentPane();23 panel=newMypanel();24 panel.setBackground(Color.ORANGE);25 cp.add(panel,BorderLayout.CENTER);26 }27

28 public static voidmain(String[] args) {29 JFrame frame=newDrawFrame();30 frame.setVisible(true);31

32 }33

34 }

【Mypanel】

1 packageqipan;2

3 importjava.awt.Color;4 importjava.awt.Graphics;5 importjava.awt.Image;6 importjava.awt.Point;7 importjava.awt.event.MouseAdapter;8 importjava.awt.event.MouseEvent;9 importjava.awt.event.MouseListener;10 importjava.io.File;11 importjava.io.IOException;12

13 importjavax.imageio.ImageIO;14 importjavax.swing.JOptionPane;15 importjavax.swing.JPanel;16

17 public class Mypanel extendsJPanel {18 //属性

19 /**棋盘宽度*/

20 public static final int GRID_WIDTH = 40;21 /**棋盘行数*/

22 public static final int LINE_COUNT = 15;23 /**黑子与白子*/

24 public static final int ITEM_BLACK = 1;25 public static final int ITEM_WHITE = 2;26

27 /**黑棋和白棋的图片*/

28 Image imgblack = null;29 Image imgwhite = null;30

31 /**设置分数机制*/

32 String[] blackKey ={33 "11111", "011110", "11110", "01111", "10111",34 "11011", "11101", "01110", "11100", "00111",35 "0111", "1011","1101", "1110", "111",36 "01100", "00110", "011", "110", "11"};37

38 String[] whiteKey ={39 "22222", "022220", "22220", "02222", "20222",40 "22022", "22202", "02220", "22200", "00222",41 "0222", "2022","2202", "2220", "222",42 "02200", "00220", "022", "220", "22"};43

44 int[] Keyvalue ={45 100, 90, 80, 80, 80,46 80, 80, 70, 60, 60,47 50, 50, 50, 50, 40,48 30, 30, 20, 20, 10};49 /**设置计算机为黑色(true),人为白色(false)*/

50 private boolean isblack = true;51 /**绘制棋盘数组*/

52 int[][] chessItems = new int[LINE_COUNT][LINE_COUNT];53 /**创建监听器对象*/

54 private static MouseListener listener = null;55

56 private Point lastItemPoint = newPoint();57 //方法

58 publicMypanel() {59

60 //加载图片

61 try{62 imgblack = ImageIO.read(new File("imgs/black.png "));63 imgwhite = ImageIO.read(new File("imgs/white.png "));64 } catch(IOException e) {65 e.printStackTrace();66 }67 //添加监听器

68 listener = newMyListener();69 this.addMouseListener(listener);70 }71

72 //添加鼠标监听器

73 public class MyListener extendsMouseAdapter {74 @Override75 public voidmouseClicked(MouseEvent e) {76 int x =e.getX();77 int y =e.getY();78 int row = y /GRID_WIDTH;79 int col = x /GRID_WIDTH;80 //绘制落点棋子,并置换一次棋子颜色

81 if (chessItems[row][col] == 0) {82 if(isblack) {83 chessItems[row][col] =ITEM_WHITE;84 isblack = !isblack;85 } else{86 isblack = !isblack;87 chessItems[row][col] =ITEM_BLACK;88 }89 Mypanel.this.repaint();90 }91 //判断胜负

92 boolean Result =checkWin(row, col);93

94 //重置棋盘

95 if(Result) {96 JOptionPane.showMessageDialog(null, "you won");97 reset();98 }99

100 //电脑下棋

101 computerPlay();102 }103 /**电脑*/

104 private voidcomputerPlay() {105 int temRow = -1, temCol = -1, maxValue = 0;106 int current = isblack ? 2 : 1;107 for (int row = 0; row < LINE_COUNT; row++) {108 for (int col = 0; col < LINE_COUNT; col++) {109 if (chessItems[row][col] > 0)110 continue;111 int attack = checkMax(row, col, current);//计算进攻值

112 /**3-current是为了置换颜色,判断防守哪个棋,减5是为了在进攻值和防守值相等时优先选择进攻*/

113 int defend = checkMax(row, col, 3-current) - 5;//计算防守值

114 int max =Math.max(attack, defend);115 if (max >maxValue) {116 temRow =row;117 temCol =col;118 maxValue =max;119 }120 }121 }122 //在计算出来的地方落子

123 if(temCol<0||temRow<0)124 {125 /**用sum来计算棋盘当前有没有下棋,如果没有下棋,则电脑不执行任何操作,直到我下棋为止*/

126 int sum=0;127 for(int i=0;i

138 }else{139 chessItems[temRow][temCol] =current;140 lastItemPoint.x=temRow;141 lastItemPoint.y=temCol;142 isblack=!isblack;//换一次手

143 repaint();//重画

144 boolean result =checkWin(temRow, temCol);145 //判断胜负

146 if(result) {147 JOptionPane.showMessageDialog(null, "you lost");148 reset();149 }150 }151 }152

153 /**

154 * 评估落子位置的分值155 *@paramrow156 *@paramcol157 *@paramcurrent158 *@return

159 */

160 private int checkMax(int row, int col, intcurrent) {161 int max=0,temMax=0;162 String [] strings =blackKey;163 if(current==2){164 strings =whiteKey;165 }166

167 //水平方向

168 StringBuilder builder = newStringBuilder();169 for(int i=-4;i<=4;i++)170 {171 int newCol=col+i;172 if(newCol<0||newCol>=LINE_COUNT) continue;173 if(i==0){174 builder.append(current);175 }else{176 builder.append(chessItems[row][newCol]);177 }178 }179

180 for(int i=0;i=0){184 max=Keyvalue[i];185 break;186 }187 }188 if(max==100)189 returnmax;190

191 //竖直方向

192 builder.delete(0, builder.length());193 for(int i=-4;i<=4;i++)194 {195 int newRow=row+i;196 if(newRow<0||newRow>=LINE_COUNT) continue;197 if(i==0){198 builder.append(current);199 }else{200 builder.append(chessItems[newRow][col]);201 }202 }203

204 for(int i=0;i=0){208 temMax=Keyvalue[i];209 break;210 }211 }212 if(temMax>max)213 max=temMax;214 if(max==100)215 returnmax;216

217 //正45度方向

218 builder.delete(0, builder.length());219 for(int i=-4;i<=4;i++)220 {221 int newRow=row-i;222 int newCol=col+i;223 if(newCol<0||newCol>=LINE_COUNT||newRow<0||newRow>=LINE_COUNT) continue;224 if(i==0){225 builder.append(current);226 }else{227 builder.append(chessItems[newRow][newCol]);228 }229 }230

231 for(int i=0;i=0){235 temMax=Keyvalue[i];236 break;237 }238 }239 if(temMax>max)240 max=temMax;241 if(max==100)242 returnmax;243

244 //负45度方向

245 builder.delete(0, builder.length());246 for(int i=-4;i<=4;i++)247 {248 int newRow=row+i;249 int newCol=col+i;250 if(newCol<0||newCol>=LINE_COUNT||newRow<0||newRow>=LINE_COUNT) continue;251 if(i==0){252 builder.append(current);253 }else{254 builder.append(chessItems[newRow][newCol]);255 }256 }257

258 for(int i=0;i=0){262 temMax=Keyvalue[i];263 break;264 }265 }266 if(temMax>max)267 max=temMax;268 if(max==100)269 returnmax;270 returnmax;271 }272 //将数组的值置为0,也就将棋盘重画为空

273 private voidreset() {274 for (int row = 0; row < LINE_COUNT; row++) {275 for (int col = 0; col < LINE_COUNT; col++) {276 chessItems[row][col] = 0;277 }278 }279 isblack = true;280 repaint();281 }282

283 private boolean checkWin(int row, intcol) {284 StringBuilder builder = newStringBuilder();285 //判断水平方向

286 for (int i = -4; i <= 4; i++) {287 int newcol = col +i;288 if (newcol >= 0 && newcol = 0 || builder.indexOf("22222") >= 0) {293 return true;294 }295 //判断竖直方向

296 builder.delete(0, builder.length());297 for (int i = -4; i <= 4; i++) {298 int newrow = row +i;299 if (newrow >= 0 && newrow = 0 || builder.indexOf("22222") >= 0) {304 return true;305 }306 //判断正45度方向

307 builder.delete(0, builder.length());308 for (int i = 4; i >= -4; i--) {309 int newrow = row +i;310 int newcol = col -i;311 if (newrow >= 0 && newrow < LINE_COUNT && newcol >= 0

312 && newcol = 0 || builder.indexOf("22222") >= 0) {317 return true;318 }319 //判断负45度方向

320 builder.delete(0, builder.length());321 for (int i = -4; i <= 4; i++) {322 int newrow = row +i;323 int newcol = col +i;324 if (newrow >= 0 && newrow < LINE_COUNT && newcol >= 0

325 && newcol = 0 || builder.indexOf("22222") >= 0) {330 return true;331 }332 return false;333 }334 }335

336 //绘制棋盘

337 @Override338 protected voidpaintComponent(Graphics g) {339 super.paintComponent(g);340 g.setColor(Color.black);341

342 //绘制水平线

343 for (int i = 0; i < LINE_COUNT; i++) {344 int x1 = GRID_WIDTH / 2;345 int y1 = GRID_WIDTH / 2 + i *GRID_WIDTH;346 int x2 = 14 * GRID_WIDTH + GRID_WIDTH / 2;347 int y2 =y1;348 g.drawLine(x1, y1, x2, y2);349 }350 //绘制垂直线

351 for (int i = 0; i < LINE_COUNT; i++) {352 int x1 = GRID_WIDTH / 2 + i *GRID_WIDTH;353 int y1 = GRID_WIDTH / 2;354 int x2 =x1;355 int y2 = GRID_WIDTH / 2 + 14 *GRID_WIDTH;356 g.drawLine(x1, y1, x2, y2);357 }358 //ChessItem(0, 2, Color.BLUE, g);359 //绘制一个棋子

360 for (int row = 0; row < LINE_COUNT; row++) {361 for (int col = 0; col < LINE_COUNT; col++) {362 switch(chessItems[row][col]) {363 caseITEM_BLACK:364 ChessItem(col, row, Color.BLACK, g);365 drawlimit(lastItemPoint,Color.RED,g);//去跟踪电脑所下的棋

366 break;367 caseITEM_WHITE:368 ChessItem(col, row, Color.WHITE, g);369 break;370 }371

372 }373 }374 }375 /**

376 * 追踪画框377 *@paramlasPoint 上一个棋子,也就是电脑所下的棋378 *@paramcolor 框体颜色379 *@paramg 画笔380 */

381 private voiddrawlimit(Point lasPoint, Color color, Graphics g) {382 int x = lasPoint.y *GRID_WIDTH;383 int y = lasPoint.x*GRID_WIDTH;384 g.setColor(color);385 g.drawRect(x, y, GRID_WIDTH, GRID_WIDTH);386 }387 /**

388 * 构建绘制棋子的方法389 *@paramcol 棋子所在列坐标390 *@paramrow 棋子所在行坐标391 *@paramcolor 棋子颜色392 *@paramg393 */

394 public void ChessItem(int col, introw, Color color, Graphics g) {395 int x = col *GRID_WIDTH;396 int y = row *GRID_WIDTH;397 //g.setColor(color);398 //g.fillOval(x, y, GRID_WIDTH, GRID_WIDTH);

399 Image image = Color.BLACK.equals(color) ?imgblack:imgwhite;400 g.drawImage(image, x, y, GRID_WIDTH, GRID_WIDTH, this);401 }402 }

java五子棋人机对战_实现简单的人机对战五子棋(实践)相关推荐

  1. Java中的变量分类_开发简单的Java应用

    第一章 开发简单的Java应用 1.Java语言的技术分类 (1)JavaSE:标准版,开发桌面应用 (2)JavaEE:企业版,Web应用 (3)JavaME:小型版,嵌入式 2.如何开发和运行Ja ...

  2. java a星寻路算法_用简单直白的方式讲解A星寻路算法原理

    很多游戏特别是rts,rpg类游戏,都需要用到寻路.寻路算法有深度优先搜索(DFS),广度优先搜索(BFS),A星算法等,而A星算法是一种具备启发性策略的算法,效率是几种算法中最高的,因此也成为游戏中 ...

  3. java语言编写简易表达式_将简单的表达语言放入Java

    小编典典 您可以看到如何传递所有参数: ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = m ...

  4. python大作业五子棋人人对战_简单的五子棋(人人对战)

    这是一个简单的五子棋游戏,目前只实现了简单的人人对战,就是自己跟自己下...具体效果如下: 实现这个效果也很简单,主要功能是: 1.点击棋盘能下棋子.棋子位置在棋盘点.点击点和下子点近似判断.黑白棋子 ...

  5. python五子棋人人对战_简单的五子棋-人人对战

    1新建工程 项目->VC++->MFC->MFC应用程序->输入名称->单文档->Window套接字->完成 2资源编辑 视图->其他窗口->资源 ...

  6. python五子棋人人对战_五子棋-人人对战

    date: 2019-03-07 五子棋是国内受到普遍欢迎的一款游戏,规则简单,趣味不俗.作为一名程序员,自然也希望将它移植到电脑上. 这篇我们要讲的主要就是实现简单的人人对战,AI算法放到以后单独说 ...

  7. java mysql防重复提交_防止数据重复提交的6种方法(超简单)!

    有位朋友,某天突然问磊哥:在 Java 中,防止重复提交最简单的方案是什么? 这句话中包含了两个关键信息,第一:防止重复提交:第二:最简单. 于是磊哥问他,是单机环境还是分布式环境? 得到的反馈是单机 ...

  8. Java程序如何写判断闰年_用Java程序判断是否是闰年的简单实例

    我们知道,(1)如果是整百的年份,能被400整除的,是闰年:(2)如果不是整百的年份,能被4整除的,也是闰年.每400年,有97个闰年.鉴于此,程序可以作以下设计: 第一步,判断年份是否被400整除, ...

  9. 编写java判断闰年_用Java程序判断是否是闰年的简单实例

    我们知道,(1)如果是整百的年份,能被400整除的,是闰年:(2)如果不是整百的年份,能被4整除的,也是闰年.每400年,有97个闰年.鉴于此,程序可以作以下设计: 第一步,判断年份是否被400整除, ...

最新文章

  1. torch 多进程卡死
  2. python编程16章_Python核心编程——Chapter16
  3. python find(urlopen.read())_Python小白必看之urlopen()详解
  4. Managing the Lifecycle of a Bound Service
  5. Github Page 绑定域名
  6. 别人在加薪,你却在加班?快到这里和聪明的小伙伴一起充电吧!
  7. pythontkinter界面切换效果_python tkinter实现界面切换的示例代码
  8. JS(JQUERY)操作框架页面全集
  9. JS判断一个页面是否已经打开
  10. 太牛X了,大四学生自创文言文编程语言,Hello World竟然这样写!?
  11. [2.1]-AutoSAR零基础学习-汽车电子控制系统简介
  12. Android总结笔记04:仿QQ空间登录UI,解决软键盘弹出挡住输入框的问题
  13. IPv6 节点主动访问 IPv4 节点-地址池方式的NAT64配置
  14. 共享计算机用户帐户限制怎么办,win7系统使用共享功能被提示用户账户限制的解决方法...
  15. 渗透测试的介绍和防范
  16. 如何让ie窗口显示到最前面
  17. 每日一题(4.27 - 5.2)
  18. ubuntu php mysql 乱码,ubuntu 服务器字符乱码问题
  19. HTTP 新增的 103 状态码,这次终于派上用场了!
  20. Python 当当网数据分析

热门文章

  1. 怎么打钩_如何在excel中打钩
  2. 考研英语一和英语二的区别
  3. CUDA编程:与OpenCV结合
  4. 网页现现实理服务器没有响应,前端_网页编程 HTTP协议(进阶)
  5. 大鱼吃豆子游戏java_java swing开发简单的大鱼吃豆子小游戏,可用于毕业设计(附详细设计文档)...
  6. 【SAM】loj#6401. 字符串
  7. jq的each方法之退出循环与继续循环
  8. [资料]自动化e2e测试 -- WebDriverJS,Jasmine和Protractor
  9. 2)Java中的==和equals
  10. HDU1568 Fibonacci【斐波拉契数列】