当前位置: 首页 > news >正文

在线五子棋对战 --- 人机对战的实现

文章目录

  • 1. 人机对战
    • 1.1 演示
    • 1.2 评分表
    • 1.3 算法思路
    • 1.4 具体代码
      • 1.4.1 评分表方法
      • 1.4.2 横向得分方法
      • 1.4.3 纵向得分方法
      • 1.4.4 左斜得分方法
      • 1.4.5 右斜得分方法
      • 1.4.6 落子总得分方法
      • 1.4.7 确认落子位置的方法

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

相关文章:

  • 【微信小程序】shrio安全登录界面实现
  • Apache网页的优化,安全与防盗链
  • python中Try的运用及意义
  • React中实现插槽效果的方案
  • 一起Talk Android吧(第三百八十九回:介绍两种实现倒计时的方法)
  • SystemVerilog——线程以及线程之间的通信
  • Node.js 应用开发详解开篇词 Node.j 从工程化工具到后端服务应用的转变
  • 【Android】Android Binder进程间通信AIDL示例与源码分析
  • ARM学习(12)基于arm架构的嵌入式操作系统理解
  • pytorch利用hook【钩子】获取torch网络每层结构【附代码】
  • 快速了解Nginx的基本介绍
  • 字符串统计:strlen函数的讲解,及其模拟实现
  • Linux——什么是环境变量?
  • 关于软件定时器的一些讨论
  • 睿智的目标检测60——Pytorch搭建YoloV7目标检测平台
  • 时间复杂度分析经典问题——最大子序列和
  • android 一些 utils
  • Angular 4.x 动态创建组件
  • HTTP--网络协议分层,http历史(二)
  • Javascript Math对象和Date对象常用方法详解
  • java取消线程实例
  • Laravel 实践之路: 数据库迁移与数据填充
  • Next.js之基础概念(二)
  • nodejs调试方法
  • orm2 中文文档 3.1 模型属性
  • Promise面试题2实现异步串行执行
  • Terraform入门 - 1. 安装Terraform
  • Vue.js源码(2):初探List Rendering
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 关于字符编码你应该知道的事情
  • 规范化安全开发 KOA 手脚架
  • 理解 C# 泛型接口中的协变与逆变(抗变)
  • 如何编写一个可升级的智能合约
  • 一份游戏开发学习路线
  • 怎么将电脑中的声音录制成WAV格式
  • 自定义函数
  • ​香农与信息论三大定律
  • #WEB前端(HTML属性)
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • #前后端分离# 头条发布系统
  • (04)odoo视图操作
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (一)认识微服务
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • .apk文件,IIS不支持下载解决
  • .NET Framework 服务实现监控可观测性最佳实践
  • .Net 中Partitioner static与dynamic的性能对比
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .NET关于 跳过SSL中遇到的问题