Java五子棋算法

来源:互联网 发布:偷看微信聊天记录软件 编辑:程序博客网 时间:2024/06/06 14:11

期中作业用 Java 写了个五子棋,感觉还挺有意思的,分享一下。



核心算法:

首先得为整个棋盘建立一张表格用以记录棋子信息,我们使用一个15*15的二维数组 Table[15][15] (15*15是五子棋棋盘的大小),数组的每一个元素对应棋盘上的一个交叉点,用“0”表示空位、“1”代表己方的子、“2”代表对方的子;这张表也是之后分析的基础。

在此之后还要为电脑和玩家双方各建立一张棋型表Computer[15][15][5]和Player[15][15][5],用来存放棋型数据,就是刚才所说的重要程度,比如用“20”代表“冲四”的点,用“15”代表“活三”的点,那么在计算重要性时,就可以根据20>15得出前者比后者重要,下子时电脑便会自动选择“冲四”的点。那为什么棋型表要使用三维数组呢?因为棋盘上的每一个点都可以与横、竖、左斜、右斜四个方向的棋子构成不同的棋型,还要算出他们的和,所以一个点总共有5个记录;这样做的另一个好处是可以轻易判断出复合棋型,例如:如果同一点上有2个“15”就是双三、有一个“15”和一个“20”就是四三。

先来分析己方的棋型,我们从棋盘左上角出发,向右逐行搜索,当遇到一个空白点时,以它为中心向左挨个查找,如果遇到己方的子则记录然后继续,如果遇到对方的子、空白点或边界就停止查找。左边完成后再向右进行同样的操作;最后把左右两边的记录合并起来,得到的数据就是该点横向上的棋型,然后把棋型的编号填入到Computer[x][y][n]中就行了(x、y代表坐标,n=0、1、2、3分别代表横、竖、左斜、右斜四个方向)。而其他三个方向的棋型也可用同样的方法得到,当搜索完整张棋盘后,己方棋型表也就填写完毕了。然后再用同样的方法填写对方棋型表。有了上面填写的两张棋型表,现在要作的就是让电脑知道在哪一点下子了。其中最简单的计算方法,就是遍历棋型表Computer[15][15][5]和Player[15][15][5]找出其中数值最大的一点,在该点下子即可。

核心代码:

public class judgement {//用这个类进行各种判断(包括电脑走哪和输赢判断)public static int[] best_point(){//这个方法用来得出电脑走哪里最合适int[][] board={ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},{0,1,1,1,1,1,1,1,1,1,1,1,1,1,0},{0,1,2,2,2,2,2,2,2,2,2,2,2,1,0},{0,1,2,3,3,3,3,3,3,3,3,3,2,1,0},{0,1,2,3,4,4,4,4,4,4,4,3,2,1,0},{0,1,2,3,4,5,5,5,5,5,4,3,2,1,0},{0,1,2,3,4,5,6,6,6,5,4,3,2,1,0},{0,1,2,3,4,5,6,7,6,5,4,3,2,1,0},{0,1,2,3,4,5,6,6,6,5,4,3,2,1,0},{0,1,2,3,4,5,5,5,5,5,4,3,2,1,0},{0,1,2,3,4,4,4,4,4,4,4,3,2,1,0},{0,1,2,3,3,3,3,3,3,3,3,3,2,1,0},{0,1,2,2,2,2,2,2,2,2,2,2,2,1,0},{0,1,1,1,1,1,1,1,1,1,1,1,1,1,0},{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};//初始化棋盘int[][][] computer=new int[15][15][5];//电脑棋型评分表(包括横、竖、左斜、右斜四种以及他们的和)int[][][] player=new int[15][15][5];//玩家棋型评分表int[] result=new int[2];//最终结果(电脑下子坐标)int[][] close=new int[2][4];//端点的阻碍情况(2、4指分两种颜色的棋,四个方向,下同)int[][] continued=new int[2][4];//连续几个子(两边加起来)int[][] continued_1=new int[2][4];//向一边连续几个子int[][] continued_2=new int[2][4];//向另一边连续几个子int opposite;//对立面颜色代号for(int i=0;i<15;i++){for(int j=0;j<15;j++){for(int k=0;k<4;k++){computer[i][j][k]=0;player[i][j][k]=0;//初始化为0}}}for(int i=0;i<2;i++){for(int j=0;j<4;j++){close[i][j]=0;continued[i][j]=0;continued_1[i][j]=0;continued_2[i][j]=0;//初始化为0}}int point=0;for(int i=0;i<15;i++){//对棋盘上每个点进行分析for(int j=0;j<15;j++){if(main_loop.table[i][j]==0){//首先该位置上不能有子(table是用于记录棋盘上的棋子的二维数组,没有棋子为0,电脑为1,玩家为2)for(int side=0;side<2;side++){//分别对黑子和白子进行棋形分析if(side==0){opposite=2;}else{opposite=1;//根据当前分析的颜色确定其对立面}close[side][0]=0;close[side][1]=0;close[side][2]=0;close[side][3]=0;//初始化为0if(i==0 || i==14){//棋盘左右两边缘的情况close[side][1]+=1;close[side][2]+=1;close[side][3]+=1;}if(j==0 || j==14){//棋盘上下两边缘的情况close[side][0]+=1;if(i!=0 && i!=14){//既在棋盘左右两边又在上下两边即在角落时的情况close[side][2]+=1;close[side][3]+=1;}}for(int k=j+1;k<15;k++){//竖直方向向上的情况if(main_loop.table[i][k]==0){//端点为空continued_1[side][0]=k-j-1;break;}else if(main_loop.table[i][k]==opposite){//端点为对立棋子continued_1[side][0]=k-j-1;close[side][0]+=1;break;}if(k==14){//遇到棋盘上边缘close[side][0]+=1;}}for(int k=j-1;k>=0;k--){//竖直方向向下的情况if(main_loop.table[i][k]==0){continued_2[side][0]=j-1-k;break;}else if(main_loop.table[i][k]==opposite){continued_2[side][0]=j-1-k;close[side][0]+=1;break;}if(k==0){close[side][0]+=1;}}continued[side][0]=continued_1[side][0]+continued_2[side][0]+1;//竖直方向向上+向下for(int k=i+1;k<15;k++){//水平方向向右的情况if(main_loop.table[k][j]==0){continued_1[side][1]=k-i-1;break;}else if(main_loop.table[k][j]==opposite){continued_1[side][1]=k-i-1;close[side][1]+=1;break;}if(k==14){close[side][1]+=1;}}for(int k=i-1;k>=0;k--){//水平方向向左的情况if(main_loop.table[k][j]==0){continued_2[side][1]=i-1-k;break;}else if(main_loop.table[k][j]==opposite){continued_2[side][1]=i-1-k;close[side][1]+=1;break;}if(k==0){close[side][1]+=1;}}continued[side][1]=continued_1[side][1]+continued_2[side][1]+1;for(int k=i+1,p=j+1;k<15&&p<15;k++,p++){//向右上的情况if(main_loop.table[k][p]==0){continued_1[side][2]=k-i-1;break;}else if(main_loop.table[k][p]==opposite){continued_1[side][2]=k-i-1;close[side][2]+=1;break;}if(k==14 || p==0){close[side][2]+=1;}}for(int k=i-1,p=j-1;k>=0&&p>=0;k--,p--){//向左下的情况if(main_loop.table[k][p]==0){continued_2[side][2]=i-1-k;break;}else if(main_loop.table[k][p]==opposite){continued_2[side][2]=i-1-k;close[side][2]+=1;break;}if(k==0 || p==14){close[side][2]+=1;}}continued[side][2]=continued_1[side][2]+continued_2[side][2]+1;for(int k=i+1,p=j-1;k<15&&p>=0;k++,p--){//向右下的情况if(main_loop.table[k][p]==0){continued_1[side][3]=k-i-1;break;}else if(main_loop.table[k][p]==opposite){continued_1[side][3]=k-i-1;close[side][3]+=1;break;}if(k==14 || p==0){close[side][3]+=1;}}for(int k=i-1,p=j+1;k>=0&&p<15;k--,p++){//向左上的情况if(main_loop.table[k][p]==0){continued_2[side][3]=i-1-k;break;}else if(main_loop.table[k][p]==opposite){continued_2[side][3]=i-1-k;close[side][3]+=1;break;}if(k==0 || p==14){close[side][3]+=1;}}continued[side][3]=continued_1[side][3]+continued_2[side][3]+1;for(int m=0;m<4;m++){//对于四个方向根据连续子数和端点情况给予相应的评分if(close[side][m]==0){//两端点均无子if(continued[side][m]==2){//能活2if(side==0){computer[i][j][m]=35;}else{player[i][j][m]=15;}}else if(continued[side][m]==3){//能活3if(side==0){computer[i][j][m]=800;}else{player[i][j][m]=400;}}else if(continued[side][m]==4){//能活4if(side==0){computer[i][j][m]=15000;}else{player[i][j][m]=7000;}}else if(continued[side][m]>=5){//能活5if(side==0){computer[i][j][m]=800000;}else{player[i][j][m]=100000;}}}else if(close[side][m]==1){//仅一端有子if(continued[side][m]==2){//能冲2if(side==0){computer[i][j][m]=20;}else{player[i][j][m]=5;}}else if(continued[side][m]==3){//能冲3if(side==0){computer[i][j][m]=30;}else{player[i][j][m]=10;}}else if(continued[side][m]==4){//能冲4if(side==0){computer[i][j][m]=790;}else{player[i][j][m]=390;}}else if(continued[side][m]>=5){//能冲5if(side==0){computer[i][j][m]=800000;}else{player[i][j][m]=100000;}}}else if(close[side][m]==2){//两端均有子if(continued[side][m]>=5){//小于5的情况不作考虑,因为不可能成5if(side==0){computer[i][j][m]=800000;}else{player[i][j][m]=100000;}}}if(side==0){computer[i][j][4]+=computer[i][j][m];//将一个点4个方向的评分加起来得到一个总评分}else{player[i][j][4]+=player[i][j][m];}}}}else{//如果该位置有子则给予极小的评分for(int m=0;m<4;m++){computer[i][j][m]=-100000000;computer[i][j][4]+=computer[i][j][m];}}if(computer[i][j][4]+player[i][j][4]+board[i][j]>=point){if(computer[i][j][4]+player[i][j][4]+board[i][j]==point){double choice=Math.random();if(choice>=0.5){point=computer[i][j][4]+player[i][j][4]+board[i][j];}}else{point=computer[i][j][4]+player[i][j][4]+board[i][j];}result[0]=i;result[1]=j;}}}return result;}public static int is_over(){//判断胜负的方法int[] continued=new int[4];int[] continued_1=new int[4];int[] continued_2=new int[4];for(int j=0;j<4;j++){continued[j]=0;continued_1[j]=0;continued_2[j]=0;}int result=0;int side;int i=main_loop.piece_x;int j=main_loop.piece_y;if(main_loop.table[i][j]==1){side=1;}else{side=2;}for(int k=j+1;k<15;k++){if(main_loop.table[i][k]!=side){continued_1[0]=k-j-1;break;}}for(int k=j-1;k>=0;k--){if(main_loop.table[i][k]!=side){continued_2[0]=j-1-k;break;}}continued[0]=continued_1[0]+continued_2[0]+1;for(int k=i+1;k<15;k++){if(main_loop.table[k][j]!=side){continued_1[1]=k-i-1;break;}}for(int k=i-1;k>=0;k--){if(main_loop.table[k][j]!=side){continued_2[1]=i-1-k;break;}}continued[1]=continued_1[1]+continued_2[1]+1;for(int k=i+1,p=j+1;k<15&&p<15;k++,p++){if(main_loop.table[k][p]!=side){continued_1[2]=k-i-1;break;}}for(int k=i-1,p=j-1;k>=0&&p>=0;k--,p--){if(main_loop.table[k][p]!=side){continued_2[2]=i-1-k;break;}}continued[2]=continued_1[2]+continued_2[2]+1;for(int k=i+1,p=j-1;k<15&&p>=0;k++,p--){if(main_loop.table[k][p]!=side){continued_1[3]=k-i-1;break;}}for(int k=i-1,p=j+1;k>=0&&p<15;k--,p++){if(main_loop.table[k][p]!=side){continued_2[3]=i-1-k;break;}}continued[3]=continued_1[3]+continued_2[3]+1;for(int n=0;n<4;n++){if(continued[n]>=5){//任何位置检测到连续5个以上颜色相同的则游戏结束result=side;//返回值为赢的一方}}if (result==0){//判断和棋for(int m=0;m<15;m++){for(int n=0;n<15;n++){if(main_loop.table[m][n]==0){result=3;}}}}if(result==3){result=0;//即没人赢又没有和棋则返回0}else if(result==0){result=3;//和棋则返回3}return result;}}

官方网站:http://www.jackeriss.com/gobang.htm

GitHub:https://github.com/Jackeriss/gobang

1 0
原创粉丝点击