1. 人机对战

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

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

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

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

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

到此这篇关于Java实现在线五子棋对战游戏(人机对战)的文章就介绍到这了,更多相关Java在线五子棋游戏内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Java实现在线五子棋对战游戏(人机对战)的更多相关文章

  1. jQuery实现简单的抽奖游戏

    这篇文章主要为大家详细介绍了jQuery实现简单的抽奖游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  4. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  5. 基于Python实现射击小游戏的制作

    这篇文章主要介绍了如何利用Python制作一个自己专属的第一人称射击小游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手试一试

  6. Java实现世界上最快的排序算法Timsort的示例代码

    Timsort 是一个混合、稳定的排序算法,简单来说就是归并排序和二分插入排序算法的混合体,号称世界上最好的排序算法。本文将详解Timsort算法是定义与实现,需要的可以参考一下

  7. Java日期工具类的封装详解

    在日常的开发中,我们难免会对日期格式化,对日期进行计算,对日期进行校验,为了避免重复写这些琐碎的逻辑,我这里封装了一个日期工具类,方便以后使用,直接复制代码到项目中即可使用,需要的可以参考一下

  8. Java设计模式之模板方法模式Template Method Pattern详解

    在我们实际开发中,如果一个方法极其复杂时,如果我们将所有的逻辑写在一个方法中,那维护起来就很困难,要替换某些步骤时都要重新写,这样代码的扩展性就很差,当遇到这种情况就要考虑今天的主角——模板方法模式

  9. Java 中 Class Path 和 Package的使用详解

    这篇文章主要介绍了Java 中 Class Path和Package的使用详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下

  10. java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源)

    这篇文章主要介绍了java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源),文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部