Java在线五子棋游戏
独一无二的哈密瓜 人气:01. 人机对战
要增添一个人机对战的模块, 最大的难点就是如何让人机知道下在什么位置是最好的, 不仅要具备进攻的能力, 还需要具备防守的能力.
这里当人机第一次走的时候, 采用标准开局, 下子在最中间.
当玩家走了之后, 人机就需要去判定下在什么位置合理.
这里采用的是评分表的方法来计算落子在每一个位置的分数, 根据最高分数来进行下子.
1.1 演示
1.2 评分表
分析棋形的几种情况.
例如, 自己是黑子.
"_" 代表 没有子, "1" 代表 黑子 , "0" 代表 白子
当落子只有一颗子的情况
- ① _ 1 _
- ② _ 1 0
- ③ 0 1 _
- ④ 0 1 0
当落子有两颗子的情况
- ① _ 1 1 _
- ② _ 1 1 0
- ③ 0 1 1 _
- ④ 0 1 1 0
当落子有三颗子的情况
- ① _ 1 1 1 _
- ② _ 1 1 1 0
- ③ 0 1 1 1 _
- ④ 0 1 1 1 0
当落子有四颗子的情况
- ① _ 1 1 1 1 _
- ② _ 1 1 1 1 0
- ③ 0 1 1 1 1 _
- ④ 0 1 1 1 1 0
当落子有五颗子的情况
- ① _ 1 1 1 1 1 _
- ② _ 1 1 1 1 1 0
- ③ 0 1 1 1 1 1 _
- ④ 0 1 1 1 1 1 0
这里大概的情况分为这几种, 分别对这几种情况进行一个分数的设定, 让机器人根据分数的高低优先去处理某种情况.
这里设计一种分数表
一子情况
二子情况
三子情况
四子情况
五子情况
1.3 算法思路
使用暴力搜索的方法, 将棋盘中每个空格的子, 当下子的时候, 去判定下子之后, 横向得分情况, 竖向得分情况, 左斜得分情况, 右斜的得分情况.
例如, 下子是黑子.
- 横向, 去看左边有多少个黑子, 多少白子, 去看右边有多少个黑子, 多少白子. 然后根据评分表, 算得分数.
- 纵向, 去看上方有多少黑子, 多少白子, 再去下方看有多少个黑子, 多少白子, 然后根据评分表, 算得分数.
- 左斜, 去左下方看有多少黑子, 多少白子, 再去右上方看有多少黑子, 多少白子, 然后根据评分表, 算得分数.
- 右斜. 去左上方看有多少黑子,多少白子, 再去右下方看有多少黑子, 多少白子, 然后根据评分表, 算得分数.
将四个方向的得分加起来, 算得分数, 进行下子.
这里这种算法, 只具备了进攻, 不具备防守的能力. 要想人机下棋具备防守的能力, 还需要让人机对玩家落子的分数进行评估, 如果玩家落子得分更高, 就需要考虑去防守了.
这里就让, 对每个位置, 机器人落子, 和玩家落子, 算得机器人落子的得分, 和玩家落子的得分, 对分数进行相加, 然后再去比较, 当前是最大的得分情况, 就去当前位置落子.
这里进行测试的时候, 发现出现四子的时候, 会出现不进攻 或者不防守的情况. 所以在判定的时候, 如果出现了五子连珠的情况, 首先进攻. 如果对方有四子, 自己没法五子, 首先防守.
1.4 具体代码
1.4.1 评分表方法
根据评分表来分配分数, my表示我下的棋子, his表示他下的棋子
public int score(int my,int his){ if(my > 5) return 200000; if(my == 5 && his == 0) return 200000; if(my == 5 && his == 1) return 200000; if(my == 5 && his == 2) return 200000; if(my == 4 && his == 1) return 3000; if(my == 4 && his == 0) return 50000; if(my == 4 && his == 2) return 1000; if(my == 3 && his == 0) return 3000; if(my == 3 && his == 1) return 1000; if(my == 3 && his == 2) return 500; if(my == 2 && his == 0) return 500; if(my == 2 && his == 1) return 200; if(my == 2 && his == 2) return 100; if(my == 1 && his == 0) return 100; if(my == 1 && his == 1) return 50; if(my == 1 && his == 2) return 30; return 0; }
1.4.2 横向得分方法
算得横向自己棋子数, 和他的棋子数
如果遇到空格就不计算了, 遇到别人的棋子也不计算了
public int getXScore(int x,int y, int chess){ int my = 1; int his = 0; for(int i = x-1; i >= 0; i--){ if(chess == board[i][y]){ my++; }else if(board[i][y] == 0){ break; }else{ his++; break; } } for(int i = x+1; i<board.length; i++) { if(chess == board[i][y]){ my++; }else if(board[i][y] == 0){ break; }else{ his++; break; } } return score(my,his); }
1.4.3 纵向得分方法
算得纵向自己棋子数, 和他的棋子数
如果遇到空格就不计算了, 遇到别人的棋子也不计算了
private int getYScore(int x, int y, int chess) { int my = 1; int his = 0; for(int i = y-1; i >= 0; i--){ if(chess == board[x][i]){ my++; }else if(board[x][i] == 0){ break; }else{ his++; break; } } for(int i = y+1; i < board.length; i++){ if(chess == board[x][i]){ my++; }else if(board[x][i] == 0){ break; }else{ his++; break; } } return score(my,his); }
1.4.4 左斜得分方法
算得左斜向自己棋子数, 和他的棋子数
如果遇到空格就不计算了, 遇到别人的棋子也不计算了
private int getSkewScore2(int x, int y, int chess) { int my = 1; int his = 0; for(int i = x+1,j=y-1; i<board.length && j >=0; i++,j--){ if(chess == board[i][j]){ my++; }else if(board[i][j] == 0){ break; }else{ his++; break; } } for(int i = x-1,j=y+1; i>=0 && j<board.length; i--,j++){ if(chess == board[i][j]){ my++; }else if(board[i][j] == 0){ break; }else{ his++; break; } } return score(my,his); }
1.4.5 右斜得分方法
算得右斜向自己棋子数, 和他的棋子数
如果遇到空格就不计算了, 遇到别人的棋子也不计算了
private int getSkewScore1(int x, int y, int chess) { int my = 1; int his = 0; for(int i = x-1,j =y-1; i >=0 && j>=0; i--,j--){ if(chess == board[i][j]){ my++; }else if(board[i][j] == 0){ break; }else{ his++; break; } } for(int i = x+1,j=y+1; j<board.length && i < board.length; i++,j++){ if(chess == board[i][j]){ my++; }else if(board[i][j] == 0){ break; }else{ his++; break; } } return score(my,his); }
1.4.6 落子总得分方法
这里如果自己下的子可以优先五子连珠就直接下棋.
如果没有这种情况, 再去判定是否他可以五子连珠, 如果有直接堵住
其他就计算总分数
public int getScore(int x,int y) { int numX1 = getXScore(x,y,1); int numX2 = getXScore(x,y,2); int numY1 = getYScore(x,y,1); int numY2 = getYScore(x,y,2); int skew1 = getSkewScore1(x,y,1); int skew2 = getSkewScore1(x,y,2); int skew3 = getSkewScore2(x,y,1); int skew4 = getSkewScore2(x,y,2); if(numX2 >= 200000 || numY2 >= 200000 || skew2 >= 200000 || skew4 >= 200000) { return Integer.MAX_VALUE; } if(numX1 >= 200000 || numY1 >= 200000 || skew1 >= 200000 || skew3 >= 200000){ return Integer.MAX_VALUE; } int xScore = getXScore(x,y,1)+getXScore(x,y,2); int yScore = getYScore(x,y,1)+getYScore(x,y,2); int skewScore1 = getSkewScore1(x,y,1)+getSkewScore1(x,y,2); int skewScore2 = getSkewScore2(x,y,1)+getSkewScore2(x,y,2); return xScore + yScore + skewScore1 + skewScore2; }
1.4.7 确认落子位置的方法
public int[] concluate() { int[] res = new int[2]; int max = 0; for(int i = 0; i < Constant.ROW; i++) { for(int j = 0; j < Constant.COL; j++) { if(board[i][j] != 0) { continue; } int num = getScore(i,j); if(num == 200000){ res[0] = i; res[1] = j; return res; } if(num > max) { max = num; res[0] = i; res[1] = j; } } } return res; }
加载全部内容