├── 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 --------------------------------------------------------------------------------