├── README.md
├── src
├── ChessMap.java
├── Main.java
├── MainFrame.java
├── Node.java
└── NodeFlag.java
└── 六子棋.exe
/README.md:
--------------------------------------------------------------------------------
1 | # Six-in-a-row
2 | 该六子棋程序使用Java语言编写,内置AI落子,主要由阿尔法贝塔搜索+评估函数实现,存在一定的bug,智能方面还行吧
3 | Six-in-a-row/六子棋.exe文件为打包好的可执行程序
4 | 该程序编译环境为JDK8
5 | 该程序仅用来学习交流
6 | 程序设计思路分析:https://blog.csdn.net/qq_16525829/article/details/119060452
7 |
--------------------------------------------------------------------------------
/src/ChessMap.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.Collections;
3 | import java.util.Random;
4 |
5 | public final class ChessMap {
6 | public static final int EMPTY=0;
7 | public static final int WHITE=1;
8 | public static final int BLACK=2;
9 | public static long cnt=0;
10 | public ArrayList nodes=new ArrayList<>(400);
11 | public int[][] chessmap =new int[20][20];
12 | public int[][] chessMapCount=new int[20][20];
13 | public boolean aiIsStop=false;
14 | private static final int[][] dxdy=new int[][]{{-1,-1},{-1,0},{-1,1}, {0,-1}, {0,1}, {1,-1}, {1,0}, {1,1}};
15 | private static final long[] value=new long[9];
16 | private final long[] lineEvalueSum=new long[20];//Use Index:[1,19]
17 | private final long[] cowEvalueSum=new long[20];//Use Index:[1,19]
18 | private final long[] leftEvlueSum=new long[38];
19 | //Use Index:5>1;
22 | private int AiColor;
23 | //Use Index:[5,33] besides [1,5]+[33,37] is always ZERO
24 | //when x>=y Index:20-(x-y+1)
25 | //when x allFlag(){
102 | ArrayList flags=new ArrayList<>(400);
103 | Node a= nodes.get(nodes.size()-1);
104 | Node b=null;
105 | if(nodes.size()>1)
106 | b=nodes.get(nodes.size()-2);
107 | for(int i=1;i<=19;i++){
108 | for(int j=1;j<=19;j++){
109 | if(chessmap[i][j]==EMPTY&&chessMapCount[i][j]!=0){
110 | if(Math.abs(a.x-i)<=2&&Math.abs(a.y-j)<=2)
111 | flags.add(new NodeFlag(i,j,chessMapCount[i][j]+50));
112 | else if(b!=null&&Math.abs(b.x-i)<=2&&Math.abs(b.y-j)<=2)
113 | flags.add(new NodeFlag(i,j,chessMapCount[i][j]+50));
114 | else
115 | flags.add(new NodeFlag(i,j,chessMapCount[i][j]));
116 | }
117 | }
118 | }
119 | Collections.sort(flags);
120 | //System.err.println("Size:"+flags.size());
121 | while(flags.size()>90){
122 | flags.remove(flags.size()-1);
123 | }
124 | return flags;
125 | }
126 | public void updataFlag(int x,int y,int cnt){
127 | for(int i=x-3;i<=x+3;i++){
128 | for(int j=y-3;j<=y+3;j++){
129 | if(!isInChessRange(i,j))
130 | continue;
131 | chessMapCount[i][j]+=cnt*(4-Math.max(Math.abs(x-i),Math.abs(y-j)));
132 | }
133 | }
134 | /*for(int i=1;i<=19;i++){
135 | for(int j=1;j<=19;j++){
136 | if(chessmap[i][j]==EMPTY)
137 | System.err.print(chessMapCount[i][j]+" ");
138 | else
139 | System.err.print("* ");
140 | }
141 | System.err.println();
142 | }
143 | System.err.println();*/
144 | }
145 | boolean canDrop(int x,int y){
146 | return chessmap[x][y]==EMPTY ;
147 | }
148 | public int lastChessColor(){//计算上次落子颜色
149 | if(nodes.size()<=1)
150 | return BLACK;
151 | return (nodes.size()/2&1)==1?WHITE:BLACK;
152 | }
153 | public int nextChessColor(){//计算下次落子颜色
154 | if(nodes.size()==0)
155 | return BLACK;
156 | return ((nodes.size()+1)/2&1)==1?WHITE:BLACK;
157 | }
158 | public int thisChessColor(int i){//第i个棋子颜色
159 | if(i<=1)
160 | return BLACK;
161 | return (i/2&1)==1?WHITE:BLACK;
162 | }
163 | public boolean isInChessRange(int x, int y){
164 | return x >= 1 && x <= 19 && y >= 1 && y <= 19;
165 | }
166 | public boolean isDropSuccess(int x,int y){
167 | for (int i=0;i<4;i++) {
168 | if(continuousSameColor(x,y,dxdy[i][0],dxdy[i][1])+
169 | continuousSameColor(x,y,-dxdy[i][0],-dxdy[i][1])+1>=6){
170 | return true;
171 | }
172 | }
173 | return false;
174 | }
175 | public int continuousSameColor(int x,int y,int dx,int dy){
176 | int a,b,cnt=0;
177 | a=x+dx;
178 | b=y+dy;
179 | while(isInChessRange(a,b)&&chessmap[a][b]==chessmap[x][y]){
180 | ++cnt;
181 | a+=dx;
182 | b+=dy;
183 | }
184 | return cnt;
185 | }
186 | private long getLineEvalue(int x,int y,int mainChessColor){
187 | StringBuilder s=new StringBuilder();
188 | int start=1;
189 | int cnt=0;
190 | while(start<=19){
191 | if(chessmap[x][start]!=EMPTY)
192 | break;
193 | ++start;
194 | ++cnt;
195 | }
196 | if(cnt==1){
197 | s.append('0');
198 | }else if(cnt==2){
199 | s.append("00");
200 | }else if(cnt==3){
201 | s.append("000");
202 | }else if(cnt>3){
203 | s.append("0000");
204 | }
205 | int end=19;
206 | cnt=0;
207 | while(end>=1){
208 | if(chessmap[x][end]!=EMPTY)
209 | break;
210 | --end;
211 | ++cnt;
212 | }
213 | for(int j=start;j<=end;j++){
214 | if(chessmap[x][j]==WHITE)
215 | s.append('1');
216 | else if(chessmap[x][j]==BLACK)
217 | s.append('2');
218 | else
219 | s.append('0');
220 | }
221 | if(cnt==1){
222 | s.append('0');
223 | }else if(cnt==2){
224 | s.append("00");
225 | }else if(cnt==3){
226 | s.append("000");
227 | }else if(cnt>3){
228 | s.append("0000");
229 | }
230 | return singleValue(s.toString(),mainChessColor);
231 | }
232 | private long getCowEvalue(int x,int y,int mainChessColor){
233 | StringBuilder s=new StringBuilder();
234 | int start=1;
235 | int cnt=0;
236 | while(start<=19){
237 | if(chessmap[start][y]!=EMPTY)
238 | break;
239 | ++start;
240 | ++cnt;
241 | }
242 | if(cnt==1){
243 | s.append('0');
244 | }else if(cnt==2){
245 | s.append("00");
246 | }else if(cnt==3){
247 | s.append("000");
248 | }else if(cnt>3){
249 | s.append("0000");
250 | }
251 | int end=19;
252 | cnt=0;
253 | while(end>=1){
254 | if(chessmap[end][y]!=EMPTY)
255 | break;
256 | --end;
257 | ++cnt;
258 | }
259 | for(int i=start;i<=end;i++){
260 | if(chessmap[i][y]==WHITE)
261 | s.append('1');
262 | else if(chessmap[i][y]==BLACK)
263 | s.append('2');
264 | else
265 | s.append('0');
266 | }
267 | if(cnt==1){
268 | s.append('0');
269 | }else if(cnt==2){
270 | s.append("00");
271 | }else if(cnt==3){
272 | s.append("000");
273 | }else if(cnt>3){
274 | s.append("0000");
275 | }
276 | return singleValue(s.toString(),mainChessColor);
277 | }
278 | private long getLeftSlantEvalue(int x,int y,int mainChessColor){
279 | StringBuilder s=new StringBuilder();
280 | int start_x,start_y;//左下到右上
281 | if(x+y-1<=19){
282 | start_x=x+y-1;
283 | start_y=1;
284 | }else{
285 | start_x=19;
286 | start_y=y+x-19;
287 | }
288 | int cnt=0;
289 | while (start_x>=1&&start_y<=19){
290 | if(chessmap[start_x][start_y]!=EMPTY)
291 | break;
292 | --start_x;
293 | ++start_y;
294 | ++cnt;
295 | }
296 | if(cnt==1){
297 | s.append('0');
298 | }else if(cnt==2){
299 | s.append("00");
300 | }else if(cnt==3){
301 | s.append("000");
302 | }else if(cnt>3){
303 | s.append("0000");
304 | }
305 | int end_x,end_y;
306 | if(x+y-1<=19){
307 | end_x=1;
308 | end_y=x+y-1;
309 | }else{
310 | end_x=x+y-19;
311 | end_y=19;
312 | }
313 | cnt=0;
314 | while(end_x<=19&&end_y>=1){
315 | if(chessmap[end_x][end_y]!=EMPTY)
316 | break;
317 | ++end_x;
318 | --end_y;
319 | ++cnt;
320 | }
321 | for(int i=start_x,j=start_y;i>=end_x&&j<=end_y;--i,++j){
322 | if(chessmap[i][j]==WHITE)
323 | s.append('1');
324 | else if(chessmap[i][j]==BLACK)
325 | s.append('2');
326 | else
327 | s.append('0');
328 | }
329 | if(cnt==1){
330 | s.append('0');
331 | }else if(cnt==2){
332 | s.append("00");
333 | }else if(cnt==3){
334 | s.append("000");
335 | }else if(cnt>3){
336 | s.append("0000");
337 | }
338 | return singleValue(s.toString(),mainChessColor);
339 | }
340 | private long getRightSlantEvalue(int x,int y,int mainChessColor){
341 | StringBuilder s=new StringBuilder();
342 | int start_x,start_y;//左上到右下
343 | int cnt=0;
344 | if(x<=y){
345 | start_x=1;
346 | start_y=y-x+1;
347 | }else {
348 | start_x=x-y+1;
349 | start_y=1;
350 | }
351 | while (start_x<=19&&start_y<=19){
352 | if(chessmap[start_x][start_y]!=EMPTY)
353 | break;
354 | ++start_x;
355 | ++start_y;
356 | ++cnt;
357 | }
358 | if(cnt==1){
359 | s.append('0');
360 | }else if(cnt==2){
361 | s.append("00");
362 | }else if(cnt==3){
363 | s.append("000");
364 | }else if(cnt>3){
365 | s.append("0000");
366 | }
367 | int end_x,end_y;
368 | if(x<=y){
369 | end_x=x+19-y;
370 | end_y=19;
371 | }else {
372 | end_x=19;
373 | end_y=19-x+y;
374 | }
375 | cnt=0;
376 | while(end_x>=1&&end_y>=1){
377 | if(chessmap[end_x][end_y]!=EMPTY)
378 | break;
379 | --end_x;
380 | --end_y;
381 | ++cnt;
382 | }
383 | for(int i=start_x,j=start_y;i<=end_x&&j<=end_y;i++,++j){
384 | if(chessmap[i][j]==WHITE)
385 | s.append('1');
386 | else if(chessmap[i][j]==BLACK)
387 | s.append('2');
388 | else
389 | s.append('0');
390 | }
391 | if(cnt==1){
392 | s.append('0');
393 | }else if(cnt==2){
394 | s.append("00");
395 | }else if(cnt==3){
396 | s.append("000");
397 | }else if(cnt>3){
398 | s.append("0000");
399 | }
400 | return singleValue(s.toString(),mainChessColor);
401 | }
402 | private long getPointEvalue(int x,int y,int mainChessColor){
403 | return getLineEvalue(x,y,mainChessColor)+
404 | getCowEvalue(x,y,mainChessColor)+
405 | getLeftSlantEvalue(x,y,mainChessColor)+
406 | getRightSlantEvalue(x,y,mainChessColor);
407 | }
408 | private long getPointEvalue(int x,int y){
409 | if(x>=y)
410 | return lineEvalueSum[x]+lineEvalueSum[y]+leftEvlueSum[x+y-1]+rightEvalueSum[20-(x-y+1)];
411 | return lineEvalueSum[x]+lineEvalueSum[y]+leftEvlueSum[x+y-1]+rightEvalueSum[38-(20-(y-x+1))];
412 | }
413 | private long singleValue(String str,int mainChessColor){
414 | int otherChessColor=(mainChessColor==WHITE)?BLACK:WHITE;
415 | return singleValue(str,0,mainChessColor)-(long)(1.1*singleValue(str,0,otherChessColor));
416 | }
417 | private long singleValue(String str, int valuestart, int mainChessColor){
418 | if(str.length()<6)
419 | return 0;
420 | int[] n= calcValue(str, valuestart,mainChessColor);
421 | long ans=0;
422 | if(n!=null)
423 | ans+=singleValue(str.substring(0,n[0]), valuestart +1,mainChessColor)+
424 | singleValue(str.substring(n[1]),0,mainChessColor)+value[n[2]];
425 | return ans;
426 | }
427 | private int[] calcValue(String str, int valuestart, int mainChessColor){//返回值 1:index 2:index+length 3:firstvalue
428 | int temp;
429 | if(mainChessColor==WHITE){
430 | for(int i = valuestart; i=1;i--){
465 | rightEvalueSum[20-i]=getRightSlantEvalue(i,1,mainChessColor);
466 | ans+=rightEvalueSum[20-i];
467 | }
468 | for(int j=2;j<=19;j++){
469 | rightEvalueSum[18+j]=getRightSlantEvalue(1,j,mainChessColor);
470 | ans+=rightEvalueSum[18+j];
471 | }
472 | return ans;
473 | }
474 | private long beta(int depth,long alpha,long beta,long valueSum,int mainChessColor,ArrayList flags){
475 | if (depth == 0) {
476 | return valueSum;
477 | }
478 | NodeFlag a,b;
479 | long value;
480 | int nextColor=(mainChessColor == WHITE) ? BLACK : WHITE;
481 | int size=flags.size();
482 | long temp_a,temp_aa;//old new
483 | long temp_b,temp_bb;
484 | long[][] Old=new long[2][4];
485 | long[][] New=new long[2][4];
486 | for(int i=0;i=a.y)
494 | Old[0][3]=rightEvalueSum[20-(a.x-a.y+1)];
495 | else
496 | Old[0][3]=rightEvalueSum[38-(20-(a.y-a.x+1))];
497 | chessmap[a.x][a.y]=mainChessColor;
498 | if(isDropSuccess(a.x,a.y)){
499 | chessmap[a.x][a.y]=EMPTY;
500 | return -INF;
501 | }
502 | New[0][0]=getLineEvalue(a.x,a.y,AiColor);
503 | New[0][1]=getCowEvalue(a.x,a.y,AiColor);
504 | New[0][2]=getLeftSlantEvalue(a.x,a.y,AiColor);
505 | New[0][3]=getRightSlantEvalue(a.x,a.y,AiColor);
506 | temp_a=Old[0][0]+Old[0][1]+Old[0][2]+Old[0][3];
507 | valueSum-=temp_a;
508 | temp_aa=New[0][0]+New[0][1]+New[0][2]+New[0][3];
509 | valueSum+=temp_aa;
510 | for(int j=i+1;j=b.y)
522 | Old[1][3]=rightEvalueSum[20-(b.x-b.y+1)];
523 | else
524 | Old[1][3]=rightEvalueSum[38-(20-(b.y-b.x+1))];
525 | chessmap[b.x][b.y]=mainChessColor;
526 | New[1][0]=getLineEvalue(b.x,b.y,AiColor);
527 | New[1][1]=getCowEvalue(b.x,b.y,AiColor);
528 | New[1][2]=getLeftSlantEvalue(b.x,b.y,AiColor);
529 | New[1][3]=getRightSlantEvalue(b.x,b.y,AiColor);
530 | temp_b=Old[1][0]+Old[1][1]+Old[1][2]+Old[1][3];
531 | valueSum-=temp_b;
532 | temp_bb=New[1][0]+New[1][1]+New[1][2]+New[1][3];
533 | valueSum+=temp_bb;
534 | if(!isDropSuccess(b.x,b.y)){
535 | value=alpha(depth-1,alpha,beta,valueSum,nextColor,flags)-chessMapCount[a.x][a.y]-chessMapCount[b.x][b.y];
536 | }else{
537 | value=-INF;
538 | }
539 | chessmap[b.x][b.y] = EMPTY;
540 | valueSum-=temp_bb;
541 | valueSum+=temp_b;
542 | lineEvalueSum[b.x]=Old[1][0];
543 | cowEvalueSum[b.y]=Old[1][1];
544 | leftEvlueSum[b.x+b.y-1]=Old[1][2];
545 | if(b.x>=b.y)
546 | rightEvalueSum[20-(b.x-b.y+1)]=Old[1][3];
547 | else
548 | rightEvalueSum[38-(20-(b.y-b.x+1))]=Old[1][3];
549 | if(value=beta){
552 | chessmap[a.x][a.y]=EMPTY;
553 | lineEvalueSum[a.x]=Old[0][0];
554 | cowEvalueSum[a.y]=Old[0][1];
555 | leftEvlueSum[a.x+a.y-1]=Old[0][2];
556 | if(a.x>=a.y)
557 | rightEvalueSum[20-(a.x-a.y+1)]=Old[0][3];
558 | else
559 | rightEvalueSum[38-(20-(a.y-a.x+1))]=Old[0][3];
560 | return beta;
561 | }
562 | }
563 | chessmap[a.x][a.y] = EMPTY;
564 | valueSum-=temp_aa;
565 | valueSum+=temp_a;
566 | lineEvalueSum[a.x]=Old[0][0];
567 | cowEvalueSum[a.y]=Old[0][1];
568 | leftEvlueSum[a.x+a.y-1]=Old[0][2];
569 | if(a.x>=a.y)
570 | rightEvalueSum[20-(a.x-a.y+1)]=Old[0][3];
571 | else
572 | rightEvalueSum[38-(20-(a.y-a.x+1))]=Old[0][3];
573 | }
574 | return beta;
575 | }
576 | private long alpha(int depth,long alpha,long beta,long valueSum,int mainChessColor,ArrayList flags) {
577 | ++cnt;
578 | return valueSum;//tuo depth;
579 | }
580 | public ArrayList maxMin(int depth,int mainChessColor){
581 | long alpha=-INF;
582 | long beta=INF;
583 | AiColor=mainChessColor;
584 | ArrayList bestNode=new ArrayList<>();
585 | ArrayList flags=allFlag();
586 | long valueSum=evalue(AiColor);
587 | long value = 0;
588 | int nextColor=mainChessColor==WHITE?BLACK:WHITE;
589 | int size=flags.size();
590 | NodeFlag a,b;
591 | long temp_a,temp_aa;//old new
592 | long temp_b,temp_bb;
593 | long[][] Old=new long[2][4];
594 | long[][] New=new long[2][4];
595 | for(int i=0;i=a.y)
603 | Old[0][3]=rightEvalueSum[20-(a.x-a.y+1)];
604 | else
605 | Old[0][3]=rightEvalueSum[38-(20-(a.y-a.x+1))];
606 | chessmap[a.x][a.y]=mainChessColor;
607 | if (isDropSuccess(a.x, a.y)) {
608 | chessmap[a.x][a.y] = EMPTY;
609 | bestNode.clear();
610 | bestNode.add(new Node(a.x,a.y));
611 | return bestNode;
612 | }
613 | New[0][0]=getLineEvalue(a.x,a.y,AiColor);
614 | New[0][1]=getCowEvalue(a.x,a.y,AiColor);
615 | New[0][2]=getLeftSlantEvalue(a.x,a.y,AiColor);
616 | New[0][3]=getRightSlantEvalue(a.x,a.y,AiColor);
617 | temp_a=Old[0][0]+Old[0][1]+Old[0][2]+Old[0][3];
618 | valueSum-=temp_a;
619 | temp_aa=New[0][0]+New[0][1]+New[0][2]+New[0][3];
620 | valueSum+=temp_aa;
621 | for(int j=i+1;j=b.y)
633 | Old[1][3]=rightEvalueSum[20-(b.x-b.y+1)];
634 | else
635 | Old[1][3]=rightEvalueSum[38-(20-(b.y-b.x+1))];
636 | chessmap[b.x][b.y]=mainChessColor;
637 | New[1][0]=getLineEvalue(b.x,b.y,AiColor);
638 | New[1][1]=getCowEvalue(b.x,b.y,AiColor);
639 | New[1][2]=getLeftSlantEvalue(b.x,b.y,AiColor);
640 | New[1][3]=getRightSlantEvalue(b.x,b.y,AiColor);
641 | temp_b=Old[1][0]+Old[1][1]+Old[1][2]+Old[1][3];
642 | valueSum-=temp_b;
643 | temp_bb=New[1][0]+New[1][1]+New[1][2]+New[1][3];
644 | valueSum+=temp_bb;
645 | if (!isDropSuccess(b.x, b.y)) {
646 | value=beta(depth-1,alpha,beta,valueSum,nextColor,flags)+chessMapCount[a.x][a.y]+chessMapCount[b.x][b.y];
647 | }else{
648 | chessmap[a.x][a.y] = EMPTY;
649 | chessmap[b.x][b.y] = EMPTY;
650 | bestNode.clear();
651 | bestNode.add(new Node(a.x,a.y));
652 | bestNode.add(new Node(b.x,b.y));
653 | return bestNode;
654 | }
655 | chessmap[b.x][b.y] = EMPTY;
656 | valueSum-=temp_bb;
657 | valueSum+=temp_b;
658 | lineEvalueSum[b.x]=Old[1][0];
659 | cowEvalueSum[b.y]=Old[1][1];
660 | leftEvlueSum[b.x+b.y-1]=Old[1][2];
661 | if(b.x>=b.y)
662 | rightEvalueSum[20-(b.x-b.y+1)]=Old[1][3];
663 | else
664 | rightEvalueSum[38-(20-(b.y-b.x+1))]=Old[1][3];
665 | if(value==alpha){
666 | bestNode.add(new Node(a.x,a.y));
667 | bestNode.add(new Node(b.x,b.y));
668 | }
669 | if(value>alpha){
670 | alpha=value;
671 | bestNode.clear();
672 | bestNode.add(new Node(a.x,a.y));
673 | bestNode.add(new Node(b.x,b.y));
674 | }
675 | }
676 | chessmap[a.x][a.y] = EMPTY;
677 | valueSum-=temp_aa;
678 | valueSum+=temp_a;
679 | lineEvalueSum[a.x]=Old[0][0];
680 | cowEvalueSum[a.y]=Old[0][1];
681 | leftEvlueSum[a.x+a.y-1]=Old[0][2];
682 | if(a.x>=a.y)
683 | rightEvalueSum[20-(a.x-a.y+1)]=Old[0][3];
684 | else
685 | rightEvalueSum[38-(20-(a.y-a.x+1))]=Old[0][3];
686 | }
687 | int rand= new Random().nextInt(bestNode.size()/2);
688 | ArrayList temp=new ArrayList<>();
689 | temp.add(bestNode.get(rand*2));
690 | temp.add(bestNode.get(rand*2+1));
691 | return temp;
692 | }
693 | }
694 |
--------------------------------------------------------------------------------
/src/Main.java:
--------------------------------------------------------------------------------
1 | public class Main {
2 | public static void main(String[] args) {
3 | new MainFrame();
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/MainFrame.java:
--------------------------------------------------------------------------------
1 | import javax.swing.*;
2 | import java.awt.*;
3 | import java.awt.event.*;
4 | import java.io.BufferedWriter;
5 | import java.io.File;
6 | import java.io.FileWriter;
7 | import java.io.IOException;
8 | import java.text.SimpleDateFormat;
9 | import java.util.ArrayList;
10 | import java.util.Date;
11 | import java.util.LinkedList;
12 |
13 | public final class MainFrame extends JFrame {
14 | private final int Size=1000;
15 | public final int Max=19;
16 | private static JPanel jpLeft;
17 | private static JPanel jpRight;
18 | private static final String strTime="00:00:00 00";
19 | private final LinkedList firstTime=new LinkedList<>();
20 | private final LinkedList lastTime=new LinkedList<>();
21 | private int personColor;
22 | private Label firstLabel;
23 | private Label lastLabel;
24 | private JButton firstHand;
25 | private JButton lastHand;
26 | private JButton repentance;
27 | private JButton continu;
28 | private JButton restar;
29 | private JButton save;
30 | private JScrollPane jScrollPane;
31 | private JTextArea jTextArea;
32 | private ChessMap chessMap=new ChessMap();
33 | private TimerThread thred;
34 | private final AddActionListener addActionListener=new AddActionListener();
35 | MainFrame(){
36 | setTitle("六子棋");
37 | setBounds(300,10,1320,1020);
38 | JSplitPane jsp=new JSplitPane();
39 | jpLeftInit();
40 | jsp.setLeftComponent(jpLeft);
41 | jsp.setDividerSize(1);
42 | JpRightInit();
43 | jsp.setRightComponent(jpRight);
44 | jsp.setContinuousLayout(true);
45 | jsp.setDividerLocation(1000);
46 | jsp.setEnabled(false);// 禁止拖动分割条
47 | setContentPane(jsp);
48 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
49 | setResizable(false);
50 | setVisible(true);
51 | }
52 | private void jpLeftInit(){
53 | jpLeft=new JPanel(){//绘制棋盘,匿名类
54 | @Override
55 | public void paint(Graphics g){
56 | g.clearRect(0,0,Size,Size+20);
57 | g.setColor(Color.ORANGE);
58 | g.fillRect(0,0,Size,Size+20);
59 | Graphics2D g2 = (Graphics2D)g;
60 | g2.setColor(Color.BLACK);
61 | g2.setStroke(new BasicStroke(2.0f));
62 | for(int i=1;i<=Max;i++){
63 | g2.drawLine(50,i*50,950,i*50);
64 | g2.drawLine(i*50,50,i*50,950);
65 | }
66 | Font font=new Font("黑体",Font.BOLD,20);
67 | g2.setFont(font);
68 | for(int i=1;i<=Max;i++){
69 | g2.drawString(Character.toString((char)('A'+i-1)),i*50-5,975);
70 | g2.drawString(Integer.toString(19-i+1),10,i*50+6);
71 | }
72 | g2.fillOval(194,194,12,12);
73 | g2.fillOval(794,194,12,12);
74 | g2.fillOval(494,494,12,12);
75 | g2.fillOval(194,794,12,12);
76 | g2.fillOval(794,794,12,12);
77 | int size= chessMap.nodes.size();
78 | if(size==0)
79 | return;
80 | Node node= chessMap.nodes.get(0);
81 | g.fillOval(node.y*50-20,node.x*50-20,40,40);
82 | g.setColor(Color.RED);
83 | g.drawString(Integer.toString(1),node.y*50-5,node.x*50+5);
84 | for(int i = 1; i< size; i++){
85 | node= chessMap.nodes.get(i);
86 | if((i-1)%4==0||(i-2)%4==0){
87 | g.setColor(Color.WHITE);
88 | }else{
89 | g.setColor(Color.BLACK);
90 | }
91 | g.fillOval(node.y*50-20,node.x*50-20,40,40);
92 | g.setColor(Color.RED);
93 | if(i+1<10){
94 | g.drawString(Integer.toString(i+1),node.y*50-5,node.x*50+5);
95 | }else if(i+1<100){
96 | g.drawString(Integer.toString(i+1),node.y*50-8,node.x*50+5);
97 | }else{
98 | g.drawString(Integer.toString(i+1),node.y*50-11,node.x*50+5);
99 | }
100 | }
101 | if(size<=3){
102 | node= chessMap.nodes.get(0);
103 | g.drawRect(node.y*50-21,node.x*50-21,42,42);
104 | return;
105 | }
106 | if(chessMap.lastChessColor()!= chessMap.nextChessColor()){
107 | node= chessMap.nodes.get(size-1);
108 | g.drawRect(node.y*50-21,node.x*50-21,42,42);
109 | node= chessMap.nodes.get(size-2);
110 | }else{
111 | int temp=(size-2)/2*2;
112 | node= chessMap.nodes.get(temp-1);
113 | g.drawRect(node.y*50-21,node.x*50-21,42,42);
114 | node= chessMap.nodes.get(temp);
115 | }
116 | g.drawRect(node.y*50-21,node.x*50-21,42,42);
117 | }
118 | };
119 | jpLeft.addMouseListener(addActionListener);
120 | }
121 | private void JpRightInit(){
122 | jpRight=new JPanel();
123 | jpRight.setLayout(null);//空布局
124 | jpRight.setBorder(BorderFactory.createLoweredBevelBorder());
125 | Font font=new Font("黑体",Font.BOLD,18);
126 | firstLabel =new Label();
127 | firstLabel.setFont(font);
128 | firstLabel.setText(strTime);
129 | firstLabel.setBounds(190,50,150,50);
130 | jpRight.add(firstLabel);
131 | lastLabel =new Label();
132 | lastLabel.setFont(font);
133 | lastLabel.setText(strTime);
134 | lastLabel.setBounds(190,130,150,50);
135 | jpRight.add(lastLabel);
136 | ButtonActionListener buttonActionListener=new ButtonActionListener();
137 | firstHand=new JButton("先手");
138 | firstHand.setBounds(20,50,150,50);
139 | firstHand.setFont(font);
140 | firstHand.addActionListener(buttonActionListener);
141 | jpRight.add(firstHand);
142 | lastHand =new JButton("后手");
143 | lastHand.setBounds(20,130,150,50);
144 | lastHand.setFont(font);
145 | lastHand.addActionListener(buttonActionListener);
146 | jpRight.add(lastHand);
147 | repentance=new JButton("悔棋");
148 | repentance.setFont(font);
149 | repentance.setBounds(20,210,120,50);
150 | repentance.addActionListener(buttonActionListener);
151 | repentance.setEnabled(false);
152 | jpRight.add(repentance);
153 | continu=new JButton("继续");
154 | continu.setFont(font);
155 | continu.setBounds(180,210,120,50);
156 | continu.addActionListener(buttonActionListener);
157 | continu.setEnabled(false);
158 | jpRight.add(continu);
159 | restar=new JButton("重新开始");
160 | restar.setFont(font);
161 | restar.setBounds(70,290,160,50);
162 | restar.setEnabled(false);
163 | restar.addActionListener(buttonActionListener);
164 | jpRight.add(restar);
165 | save=new JButton("保存棋谱");
166 | save.setFont(font);
167 | save.setBounds(70,370,160,50);
168 | save.addActionListener(buttonActionListener);
169 | save.setEnabled(false);
170 | jpRight.add(save);
171 | jTextArea=new JTextArea("落子情况:\n");
172 | jTextArea.setFont(new Font("宋体",Font.PLAIN,20));
173 | jTextArea.setEnabled(false);//不可编辑
174 | jTextArea.setDisabledTextColor(Color.BLACK);//字体颜色
175 | jScrollPane=new JScrollPane();
176 | jScrollPane.setViewportView(jTextArea);
177 | jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
178 | jScrollPane.setBounds(60,450,200,500);
179 | jpRight.add(jScrollPane);
180 | //jTextArea.paintImmediately(jTextArea.getBounds());
181 | }
182 | private void printChess(){
183 | Node node=chessMap.nodes.get(chessMap.nodes.size()-1);
184 | if(chessMap.thisChessColor(chessMap.nodes.size())==ChessMap.WHITE){
185 | jTextArea.append("White:("+(char)('A'+node.y-1)+","+(19-node.x+1)+")\n");
186 | }else{
187 | jTextArea.append("Black:("+(char)('A'+node.y-1)+","+(19-node.x+1)+")\n");
188 | }
189 | Point p=new Point();
190 | p.setLocation(0,jTextArea.getLineCount()*20);
191 | jScrollPane.getViewport().setViewPosition(p);
192 | }
193 | private void saveChess() throws IOException {
194 | String[] name;
195 | while(true){
196 | String Str=JOptionPane.showInputDialog(this,"请输入先后手参赛队伍名,英文分号间隔","输入对话框",JOptionPane.PLAIN_MESSAGE);
197 | name=Str.split(";");
198 | if(name.length==2)
199 | break;
200 | JOptionPane.showMessageDialog(null,"输入错误,请重新输入");
201 | }
202 | Date date=new Date();
203 | SimpleDateFormat ft=new SimpleDateFormat("yyyy.MM.dd");
204 | File f = new File("C6-先手参赛队 "+name[0]+" vs 后手参赛队 "+name[1]+(chessMap.lastChessColor()==ChessMap.BLACK?"-先手胜":"-后手胜")+"-"+ft.format(date)+"安徽蚌埠-ACG.txt");
205 | if (!f.exists())
206 | f.createNewFile();
207 | BufferedWriter bw = new BufferedWriter(new FileWriter(f));
208 | ft=new SimpleDateFormat("yyyy.MM.dd HH:mm");
209 | bw.write("{[C6][先手参赛队 "+name[0]+"][后手参赛队 "+name[1]+"]["+(chessMap.lastChessColor()==ChessMap.BLACK?"先手胜":"后手胜")+"]["+ft.format(date)+" 安徽蚌埠][2021 ACG];");
210 | for (int i=0;i0){
431 | Node node=chessMap.nodes.get(chessMap.nodes.size()-1);
432 | if(chessMap.isDropSuccess(node.x,node.y)){
433 | if(chessMap.lastChessColor()==ChessMap.WHITE){
434 | JOptionPane.showMessageDialog(null,"白棋胜利,请选择重新开始/悔棋/保存棋谱");
435 | }else{
436 | JOptionPane.showMessageDialog(null,"白棋胜利,请选择重新开始/悔棋/保存棋谱");
437 | }
438 | return;
439 | }
440 | }
441 | int x = e.getY();
442 | int y = e.getX();
443 | if (x < 20 || x > 970 || y < 20 || y > 970)
444 | return;
445 | if (x % 50 <= 20) {
446 | x = x / 50;
447 | } else if (x % 50 >= 30) {
448 | x = (x + 20) / 50;
449 | } else {
450 | return;
451 | }
452 | if (y % 50 <= 20) {
453 | y = y / 50;
454 | } else if (y % 50 >= 30) {
455 | y = (y + 20) / 50;
456 | } else {
457 | return;
458 | }
459 | if(!chessMap.canDrop(x,y))
460 | return;
461 | repentance.setEnabled(true);
462 | chessMap.chessmap[x][y]= chessMap.nextChessColor();
463 | chessMap.updataFlag(x,y,1);
464 | chessMap.nodes.add(new Node(x,y));
465 | repentance.setEnabled(true);
466 | printChess();
467 | if(chessMap.nodes.size()==1){
468 | thred.isStop=true;
469 | try {
470 | Thread.sleep(100);
471 | } catch (InterruptedException interruptedException) {
472 | interruptedException.printStackTrace();
473 | }
474 | }
475 | jpLeft.repaint();
476 | jpLeft.paintImmediately(jpLeft.getBounds());
477 | if(chessMap.isDropSuccess(x,y)){
478 | thred.isStop=true;
479 | if(chessMap.lastChessColor()==ChessMap.WHITE){
480 | jTextArea.append("White:win!\n");
481 | JOptionPane.showMessageDialog(null,"白棋胜利,请选择重新开始/悔棋/保存棋谱");
482 | }else{
483 | jTextArea.append("Black:win!\n");
484 | JOptionPane.showMessageDialog(null,"黑棋胜利,请选择重新开始/悔棋/保存棋谱");
485 | }
486 | Point p=new Point();
487 | p.setLocation(0,jTextArea.getLineCount()*20);
488 | jScrollPane.getViewport().setViewPosition(p);
489 | return;
490 | }
491 | if(chessMap.nodes.size()==19*19){
492 | thred.isStop=true;
493 | try {
494 | Thread.sleep(50);
495 | } catch (InterruptedException interruptedException) {
496 | interruptedException.printStackTrace();
497 | }
498 | JOptionPane.showMessageDialog(null,"平局,请选择是否重新开始/悔棋/保存棋谱");
499 | return;
500 | }
501 | if(chessMap.nextChessColor()!=personColor){
502 | jpLeft.removeMouseListener(addActionListener);
503 | thred.isStop=true;
504 | try {
505 | Thread.sleep(50);
506 | } catch (InterruptedException interruptedException) {
507 | interruptedException.printStackTrace();
508 | }
509 | AICalcThread aiCalcThread=new AICalcThread();
510 | aiCalcThread.start();
511 | }
512 | }
513 | }
514 | private class AICalcThread extends Thread{
515 | @Override
516 | public void run(){
517 | int mainChessColor=personColor==ChessMap.WHITE?ChessMap.BLACK:ChessMap.WHITE;
518 | if(mainChessColor==ChessMap.WHITE){
519 | thred=new TimerThread(lastLabel,lastTime);
520 | }else{
521 | thred=new TimerThread(firstLabel,firstTime);
522 | }
523 | thred.isStop=false;
524 | thred.start();
525 | ArrayList nodes=chessMap.maxMin(2,mainChessColor);
526 | if(chessMap.aiIsStop){
527 | thred.isStop=true;
528 | try {
529 | Thread.sleep(50);
530 | } catch (InterruptedException interruptedException) {
531 | interruptedException.printStackTrace();
532 | }
533 | jpLeft.addMouseListener(addActionListener);
534 | return;
535 | }
536 | jpLeft.addMouseListener(addActionListener);
537 | Node a=nodes.get(0);
538 | Node b=nodes.get(1);
539 | chessMap.chessmap[a.x][a.y]=mainChessColor;
540 | chessMap.nodes.add(a);
541 | chessMap.updataFlag(a.x,a.y,1);
542 | jpLeft.repaint();
543 | jpLeft.paintImmediately(jpLeft.getBounds());
544 | thred.isStop=true;
545 | try {
546 | Thread.sleep(100);
547 | } catch (InterruptedException interruptedException) {
548 | interruptedException.printStackTrace();
549 | }
550 | printChess();
551 | //System.err.println(ChessMap.cnt);
552 | if(chessMap.isDropSuccess(a.x,a.y)){
553 | thred.isStop=true;
554 | try {
555 | Thread.sleep(50);
556 | } catch (InterruptedException interruptedException) {
557 | interruptedException.printStackTrace();
558 | }
559 | if(chessMap.lastChessColor()==ChessMap.WHITE){
560 | jTextArea.append("White:win!\n");
561 | JOptionPane.showMessageDialog(null,"白棋胜利,请选择重新开始/悔棋/保存棋谱");
562 | }else{
563 | jTextArea.append("Black:win!\n");
564 | JOptionPane.showMessageDialog(null,"黑棋胜利,请选择重新开始/悔棋/保存棋谱");
565 | }
566 | Point p=new Point();
567 | p.setLocation(0,jTextArea.getLineCount()*20);
568 | jScrollPane.getViewport().setViewPosition(p);
569 | return;
570 | }
571 | chessMap.chessmap[b.x][b.y]=mainChessColor;
572 | chessMap.nodes.add(b);
573 | chessMap.updataFlag(b.x,b.y,1);
574 | jpLeft.repaint();
575 | jpLeft.paintImmediately(jpLeft.getBounds());
576 | printChess();
577 | try {
578 | Thread.sleep(100);
579 | } catch (InterruptedException e) {
580 | e.printStackTrace();
581 | }
582 | jpLeft.repaint();
583 | jpLeft.paintImmediately(jpLeft.getBounds());
584 | if(chessMap.isDropSuccess(b.x,b.y)){
585 | thred.isStop=true;
586 | try {
587 | Thread.sleep(50);
588 | } catch (InterruptedException interruptedException) {
589 | interruptedException.printStackTrace();
590 | }
591 | if(chessMap.lastChessColor()==ChessMap.WHITE){
592 | jTextArea.append("White:win!\n");
593 | JOptionPane.showMessageDialog(null,"白棋胜利,请选择重新开始/悔棋/保存棋谱");
594 | }else{
595 | jTextArea.append("Black:win!\n");
596 | JOptionPane.showMessageDialog(null,"黑棋胜利,请选择重新开始/悔棋/保存棋谱");
597 | }
598 | Point p=new Point();
599 | p.setLocation(0,jTextArea.getLineCount()*20);
600 | jScrollPane.getViewport().setViewPosition(p);
601 | return;
602 | }
603 | if(personColor==ChessMap.WHITE)
604 | thred=new TimerThread(lastLabel,lastTime);
605 | else
606 | thred=new TimerThread(firstLabel,firstTime);
607 | thred.isStop=false;
608 | thred.start();
609 | }
610 | }
611 | private class TimerThread extends Thread{
612 | public boolean isStop=true;
613 | private final Label label;
614 | private final LinkedList time;
615 | TimerThread(Label label,LinkedList time){
616 | this.label=label;
617 | this.time=time;
618 | }
619 | @Override
620 | public void run(){
621 | long updateTime=0;
622 | long lasttime=time.getLast();
623 | long pauseTime = System.currentTimeMillis();
624 | while (!isStop) {
625 | updateTime = System.currentTimeMillis() - pauseTime +lasttime;
626 | label.setText(formatch(updateTime));
627 | try {
628 | sleep(10);
629 | } catch (InterruptedException e) {
630 | e.printStackTrace();
631 | }
632 | }
633 | time.add(updateTime);
634 | }
635 | }
636 | }
637 |
--------------------------------------------------------------------------------
/src/Node.java:
--------------------------------------------------------------------------------
1 | public final class Node{//用于存储已落子坐标(x,y)
2 | int x;
3 | int y;
4 | Node(){
5 | }
6 | Node(int x,int y){
7 | this.x=x;
8 | this.y=y;
9 | }
10 | @Override
11 | public String toString() {
12 | return "Node{" +
13 | "x=" + x +
14 | ", y=" + y +
15 | '}';
16 | }
17 | }
--------------------------------------------------------------------------------
/src/NodeFlag.java:
--------------------------------------------------------------------------------
1 | public final class NodeFlag implements Comparable{
2 | int x;
3 | int y;
4 | int flag;
5 |
6 | public NodeFlag(int x, int y, int flag) {
7 | this.x = x;
8 | this.y = y;
9 | this.flag = flag;
10 | }
11 | @Override
12 | public int compareTo(NodeFlag o) {
13 | return o.flag-flag;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/六子棋.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codewarnings/Six-in-a-row/42416a7a5a9ec39396fb3b64132eef15f81ea2fc/六子棋.exe
--------------------------------------------------------------------------------