AI算法实现五子棋(java)

时间:2022-11-22 20:36:18

本文实例为大家分享了ai算法实现五子棋的具体代码,供大家参考,具体内容如下

首先,实现一个五子棋要有一个棋盘,然后在这个棋盘上我们再来画出图画,五子棋棋盘有固定的行数和列数,再加上界面的大小和菜单栏,这些数据可能很多个类都需要用到,我们可以先考虑自己写一个接口用来存储这些数据:

AI算法实现五子棋(java)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface config {
 public static final int size=703;
 //面板大小
 public static final int x0=size/19*2-8;
 public static final int y0=x0-15;
 //棋盘网格起始点
 public static final int wid=size/19;
 //行宽
 public static final int line=15;
 //行数
 public static final int chess=wid;
 //五子棋棋子大小
 
}

这个时候我们来考虑写一个五子棋界面,除了常用的界面写法之外,考虑到五子棋的悔棋和重新开始,我们需要重写paint方法,在需要的时候调用来达到更新棋盘的作用。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import java.awt.basicstroke;
import java.awt.borderlayout;
import java.awt.color;
import java.awt.dimension;
import java.awt.graphics;
import java.awt.graphics2d;
 
import javax.swing.jpanel;
 
 
public class fivebord extends jpanel implements config{
 private static final long serialversionuid = 1l;
 private int point[][]=new int [size][size];
 
 public static void main(string[] args) {
 fivebord fb = new fivebord();
 fb.showfivebord();
 }
 
 public void showfivebord() {
 //一下是关于界面的常规设置
 javax.swing.jframe jf = new javax.swing.jframe();
 jf.settitle("fivebord");
 jf.setsize(size+100, size);
 jf.setdefaultcloseoperation(3);
 jf.setlocationrelativeto(null);
 jf.setlayout(new borderlayout());
 
 jpanel jp1=new jpanel();
 jp1.setbackground(color.orange);
 jp1.setpreferredsize(new dimension(100, size));
 jf.add(jp1,borderlayout.east);
 
 javax.swing.jbutton jbu1 = new javax.swing.jbutton("悔棋");
 jp1.add(jbu1);
 
 javax.swing.jbutton jbu2 = new javax.swing.jbutton("人机");
 jp1.add(jbu2);
 
 javax.swing.jbutton jbu3 = new javax.swing.jbutton("人人");
 jp1.add(jbu3);
 
 this.setbackground(color.yellow);
 jf.add(this,borderlayout.center);
 
 jf.setvisible(true);
 
 //以下给界面添加监听器,包括画板和按钮
  drawmouse mouse=new drawmouse(this);
  jbu1.addactionlistener(mouse);
  jbu2.addactionlistener(mouse);
  jbu3.addactionlistener(mouse);
  this.addmouselistener(mouse);
  //监听器中需要考虑当前棋盘上的棋子和位置
  mouse.setpoint(point);
    
 
 }
 public void paint(graphics g) {
 super.paint(g);
 //super.paint
 //由于paint函数是界面自带的函数且在某些时候会自动调用
 //super.paint(g)表示屏蔽父类的函数内容,换做自己接下来改写的内容
 graphics2d gr = (graphics2d)g;
 gr.setstroke(new basicstroke(1));
 //2d画笔变粗度为1
 for(int i=x0;i<=x0+line*wid;i+=wid){
 for(int j=y0;j<=y0+line*wid;j+=wid){
 g.drawline(x0, j, x0+line*wid, j);
 g.drawline(i, y0, i,y0+line*wid);
 }
 }
 //画内部16格
 gr.setstroke(new basicstroke(2));
 //画笔粗度变为2
 g.drawline(x0-wid, y0-wid, x0-wid, y0+(line+1)*wid);
 g.drawline(x0-wid, y0-wid, x0+(line+1)*wid, y0-wid);
 g.drawline(x0+(line+1)*wid, y0-wid, x0+(line+1)*wid, y0+(line+1)*wid);
 g.drawline(x0-wid, y0+(line+1)*wid, x0+(line+1)*wid, y0+(line+1)*wid);
 //画四周较粗的边框(美观起见,没有实际意义)
 for(int i=x0;i<=x0+(wid*(line+1));i+=wid){
   for(int j=y0;j<=y0+(line+1)*wid;j+=wid){
   if(point[i][j]==1){
   //画黑棋
   g.setcolor(color.black);
   g.filloval(i-wid/2, j-wid/2, wid, wid);
   }
   else if(point[i][j]==2){
   //画白棋
   g.setcolor(color.white);
   g.filloval(i-wid/2, j-wid/2, wid, wid);
   }
   }
  }
 //根据point的内容画出相应的点(即棋子)
 }
 
}

最最重要的就是监听器部分了,除了具有相应的监听功能,还要在每次人下棋之后智能判断出机器所需要下的位置,于此同时,每下一个棋子,都要判断是否已经有五子连成线进而提示输赢。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
import java.awt.color;
import java.awt.graphics;
import java.awt.event.actionevent;
import java.awt.event.actionlistener;
import java.awt.event.mouseadapter;
import java.awt.event.mouseevent;
import java.util.hashmap;
 
import javax.swing.joptionpane;
 
public class drawmouse extends mouseadapter implements config,actionlistener{
 //添加动作监听器(监听按钮)和鼠标监听器(鼠标所点位置画棋子)
 private graphics g;
 private int x,y,co=1,index=0;
 private int point[][];
 private int pointweight[][]=new int [x0+(line+1)*wid][y0+(line+1)*wid];
 private int orderx[]=new int [x0+(line+1)*wid],ordery[]=new int [y0+(line+1)*wid];
 private fivebord fb;
 private int pc=0;
 public hashmap <string,integer> hm = new hashmap <string,integer>();
 //哈希表用来存放不同棋子布局下的不同权值
 
 
 drawmouse(fivebord fb) {
 this.g = fb.getgraphics();
 this.fb=fb;
 sethashmap();
 }
 //传棋子数组
 public void setpoint(int point[][]){
  this.point=point;
 }
 public void sethashmap(){
 hm.put("1", 1);
 //某一方向线上只有一个黑棋
 hm.put("12", 5);
 //某一方向线上紧接着一个黑棋有一个白棋
 hm.put("11", 10);
 hm.put("112", 15);
 //某一方向线上紧接着两个相邻的黑棋后有一个白棋(以此类推)
 hm.put("111", 100);
 hm.put("1112", 105);
 hm.put("1111", 1000);
 
 hm.put("2", 1);
 hm.put("21", 5);
 hm.put("22", 10);
 hm.put("221", 15);
 hm.put("222", 100);
 hm.put("2221", 105);
 hm.put("2222", 1000);
 }
 
 public void actionperformed(actionevent e){
 //悔棋操作,将棋子数目减一,然后重绘界面即可
 if("悔棋".equals(e.getactioncommand())&&index>0){
 system.out.println("悔棋");
 index--;
 point[orderx[index]][ordery[index]]=0;
 fb.paint(g);
 }
 //人机模式一旦点击,界面所有棋子清零,开始人机对战(pc=1)
 if("人机".equals(e.getactioncommand())){
 system.out.println("人机");
  pc=1;
  index=0;
  for(int i=x0;i<=x0+wid*line;i+=wid){
  for(int j=y0;j<=y0+wid*line;j+=wid){
  point[i][j]=0;
  }
  }
  fb.paint(g);
 }
 //人人对战,也是点击按钮棋子清零,开始人人对战(pc=0)
 if("人人".equals(e.getactioncommand())){
 system.out.println("人机");
  pc=0;
  index=0;
  for(int i=x0;i<=x0+wid*line;i+=wid){
  for(int j=y0;j<=y0+wid*line;j+=wid){
  point[i][j]=0;
  }
  }
  fb.paint(g);
 }
 }
 
 public void mouseclicked(mouseevent e) {
 x=e.getx();
 y=e.gety();
 //得到点击的点
 if((x-x0)%wid>=wid/2){
 x=x-(x-x0)%wid+wid;
 }
 else{
 x=x-(x-x0)%wid;
 }
 if((y-y0)%wid>=wid/2){
 y=y-(y-y0)%wid+wid;
 }
 else{
 y=y-(y-y0)%wid;
 }
 //对点的位置进行修正(保证每次点击都正好下在网格交汇处)
 if(point[x][y]==0&&x>=x0&&x<=x0+wid*line&&y>=y0&&y<=y0+wid*line){
 //人人对战:直接用鼠标检测,依次变换颜色黑或白
 if(pc==0){
 if(g.getcolor()==color.black){
  g.setcolor(color.white);
  co=2;
 }
 else{
  g.setcolor(color.black);
  co=1;
 }
 }
 //人机对战,每次人下过棋子之后,计算机根据现有棋盘布局对棋局分析和总和并判断机器需要下的位置
 else if(pc==1){
 g.setcolor(color.black);
 co=1;
 }
 g.filloval(x-wid/2, y-wid/2, wid, wid);
  point[x][y]=co;
  system.out.println(index+ " "+ x+" "+y);
  orderx[index]=x;
  ordery[index]=y;
  index++;
  if(exam()==0){
  //自己敲代码过程中的验证、、、、、、可以不用在意这类输出。
  system.out.println("hahahahhhaahhahah");
  if(pc==1){
  system.out.println("hehehehehehehehehehehe");
  g.setcolor(color.white);
  co=2;
  ai();
  exam();
  }
  }
 }
 
 }
 //检测是否有一方获胜,跳出提示框提示某一方获胜
 public int exam(){
 int w=0;
 for(int i=x0-wid;i<=x0+wid*(line+1);i+=wid){
 for(int j=y0-wid;j<=y0+wid*(line+1);j+=wid){
 if(point[i][j]!=0){
  int exam1=0,exam2=0,exam3=0,exam4=0;
  //水平、竖直、左斜、右斜四个方向上同色棋子相连最多的个数
  for(int t=wid;t<5*wid;t+=wid){
  if(i+t<=x0+wid*(line+1)&&point[i+t][j]==point[i][j]){
  exam1++;
  }
  if(j+t<=y0+wid*(line+1)&&point[i][j+t]==point[i][j]){
  exam2++;
  }
  if(i+t<=x0+wid*(line+1)&&j+t<=y0+wid*(line+1)&&point[i+t][j+t]==point[i][j]){
  exam3++;
  }
  if(i+t<=x0+wid*(line+1)&&j>=t&&point[i+t][j-t]==point[i][j]){
  exam4++;
  }
  }
  system.out.println(exam1+" "+exam2+" " +exam3+" "+exam4);
  if(exam1==4||exam2==4||exam3==4||exam4==4){//某一方向上同色5子相连,一方获胜
  if(point[i][j]==1){
  w=1;
  //弹出提示框
  joptionpane.showmessagedialog(null, "黑子胜");
  }
  else{
  w=2;
  joptionpane.showmessagedialog(null, "白子胜"); 
  }
  i=x0+wid*(line+1)+1;
  break;
  }
 }
 }
 }
 return w;
 }
 //ai算法
 //分别向左、香油、左下、、、、、等8个方向检测棋子布局情况并累加在该点的权值上
 //再找出图片上没有棋子并且权值最大的点下棋子
 //记得每次下棋将各个空位置的权值归0,以便下一次计算权值累加
 public void ai(){
 for(int i=x0;i<x0+wid*(line+1);i+=wid){
  for(int j=y0;j<y0+wid*(line+1);j+=wid){
 if(point[i][j]==0){
  //像右寻找
  //system.out.print("pointweight["+(i-x0)/wid+"]["+(j-y0)/wid+"]:");
  int color=0;
  string code="";
  for(int k=i+wid;k<=x0+wid*line;k+=wid){
  if(point[k][j]!=0){
  if(color==0){
  color=point[k][j];
  code+=point[k][j];
  }
  else{
  if(point[k][j]==color){
   code+=point[k][j];
  }
  else{
   code+=point[k][j];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  integer value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
  //向下寻找
//  system.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=j+wid;k<=x0+wid*line;k+=wid){
  if(point[i][k]!=0){
  if(color==0){
  color=point[i][k];
  code+=point[i][k];
  }
  else{
  if(point[i][k]==color){
   code+=point[i][k];
  }
  else{
   code+=point[i][k];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
  //向左
//  system.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=i-wid;k>=x0;k-=wid){
  if(point[k][j]!=0){
  if(color==0){
  color=point[k][j];
  code+=point[k][j];
  }
  else{
  if(point[k][j]==color){
   code+=point[k][j];
  }
  else{
   code+=point[k][j];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
  //向上
//  system.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=j-wid;k>=y0;k-=wid){
  if(point[i][k]!=0){
  if(color==0){
  color=point[i][k];
  code+=point[i][k];
  }
  else{
  if(point[i][k]==color){
   code+=point[i][k];
  }
  else{
   code+=point[i][k];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
  //向右上寻找
//  system.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=i+wid,w=j+wid;k<=x0+wid*line&&w<=y0+wid*line;k+=wid,w+=wid){
  if(point[k][w]!=0){
  if(color==0){
  color=point[k][w];
  code+=point[k][w];
  }
  else{
  if(point[k][w]==color){
   code+=point[k][w];
  }
  else{
   code+=point[k][w];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
//  system.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=i-wid,w=j-wid;k>=x0&&w>=y0;k-=wid,w-=wid){
  if(point[k][w]!=0){
  if(color==0){
  color=point[k][w];
  code+=point[k][w];
  }
  else{
  if(point[k][w]==color){
   code+=point[k][w];
  }
  else{
   code+=point[k][w];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
//  system.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=i+wid,w=j-wid;k<=x0+line*wid&&w>=y0;k+=wid,w-=wid){
  if(point[k][w]!=0){
  if(color==0){
  color=point[k][w];
  code+=point[k][w];
  }
  else{
  if(point[k][w]==color){
   code+=point[k][w];
  }
  else{
   code+=point[k][w];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
//  system.out.print(pointweight[i][j]+" ");
  code="";
  color=0;
  for(int k=i-wid,w=j+wid;k>=x0&&w<=y0+line*wid;k-=wid,w+=wid){
  if(point[k][w]!=0){
  if(color==0){
  color=point[k][w];
  code+=point[k][w];
  }
  else{
  if(point[k][w]==color){
   code+=point[k][w];
  }
  else{
   code+=point[k][w];
   break;
  }
  }
  }
  else{
  break;
  }
  }
  value=hm.get(code);
  if(value != null){
  pointweight[i][j] += value;
  }
//  system.out.println(pointweight[i][j]);
 }
 }
 }
 //寻找最大权值的点并画棋子
 int maxx=x0,maxy=y0;
  for(int i=x0;i<=x0+wid*line;i+=wid){
  for(int j=y0;j<=y0+wid*line;j+=wid){
  system.out.print(pointweight[i][j]+" ");
  if(pointweight[i][j]>pointweight[maxx][maxy]){
  maxx=i;
  maxy=j;
  }
  
  }
  system.out.println();
  }
  g.filloval(maxx-wid/2, maxy-wid/2, wid, wid);
  point[maxx][maxy]=co;
  system.out.println(index+ " "+ maxx+" "+maxy);
  orderx[index]=maxx;
  ordery[index]=maxy;
  index++;
  //全部权值归零方便下次使用
  for(int i=x0;i<=x0+wid*line;i+=wid){
  for(int j=y0;j<=y0+wid*line;j+=wid){
  pointweight[i][j]=0;
  }
  }
 }
 
}

大概就是这个样子了,权值那里设置的还是需要调整一下。运行结果截图如下:

AI算法实现五子棋(java)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/weixin_42372777/article/details/81432083