Java实现在线五子棋对战游戏(人机对战)

作者:独一无二的哈密瓜 时间:2023-01-10 19:07:29 

1. 人机对战

要增添一个人机对战的模块, 最大的难点就是如何让人机知道下在什么位置是最好的, 不仅要具备进攻的能力, 还需要具备防守的能力.

这里当人机第一次走的时候, 采用标准开局, 下子在最中间.

当玩家走了之后, 人机就需要去判定下在什么位置合理.

这里采用的是评分表的方法来计算落子在每一个位置的分数, 根据最高分数来进行下子.

1.1 演示

Java实现在线五子棋对战游戏(人机对战)

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

这里大概的情况分为这几种, 分别对这几种情况进行一个分数的设定, 让机器人根据分数的高低优先去处理某种情况.

这里设计一种分数表

一子情况

Java实现在线五子棋对战游戏(人机对战)

二子情况

Java实现在线五子棋对战游戏(人机对战)

三子情况

Java实现在线五子棋对战游戏(人机对战)

四子情况

Java实现在线五子棋对战游戏(人机对战)

五子情况

Java实现在线五子棋对战游戏(人机对战)

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;
   }

来源:https://blog.csdn.net/wwzzzzzzzzzzzzz/article/details/127061995

标签:Java,五子棋,游戏
0
投稿

猜你喜欢

  • Android 官推 kotlin-first 的图片加载库——Coil的使用入门

    2022-07-06 00:53:34
  • Spring EL表示式的运用@Value说明

    2023-03-05 02:33:19
  • C#实体类转换的两种方式小结

    2023-08-01 21:06:45
  • java使用集合实现通讯录功能

    2023-01-30 21:27:15
  • java实现九宫格拼图游戏

    2023-05-28 09:26:07
  • 解决IDEA中快捷键Alt+Enter不能使用的问题

    2022-09-14 07:54:07
  • Spring Boot 实现https ssl免密登录(X.509 pki登录)

    2023-07-28 18:46:11
  • Android开发之线程通信详解

    2022-08-21 21:37:34
  • java实现递归文件列表的方法

    2022-10-13 13:17:00
  • Java Hutool工具实现验证码生成及Excel文件的导入和导出

    2023-02-04 22:49:32
  • Java上传文件进度条的实现方法(附demo源码下载)

    2023-06-06 11:06:16
  • Activiti流程引擎对象及配置原理解析

    2023-02-11 22:20:20
  • Java内存模型final的内存语义

    2023-06-05 08:02:25
  • java Matcher匹配头尾截取替换字符串的案例

    2023-01-30 11:44:48
  • Monkeyrunner 常用按键总结

    2022-08-23 09:17:17
  • 浅析JDK12的五大重要新特性(推荐)

    2023-01-28 19:09:24
  • MyBatis动态SQL中的trim标签的使用方法

    2022-08-30 21:38:13
  • Struts2实现文件上传时显示进度条功能

    2021-10-13 05:22:22
  • Spring如何使用注解的方式创建bean

    2022-01-29 03:45:49
  • Java使用Optional实现优雅避免空指针异常

    2023-06-05 15:35:39
  • asp之家 软件编程 m.aspxhome.com