简单五子棋算法——初级篇

  • 前言
  • 设计思路
  • 算法实现
  • 后言
  • 进阶设计

前言

五子是中国古老的棋类之一,是老少咸宜的娱乐项目。也是人机博弈中最简单的一类,相较于围棋、象棋变化更少,算法实现起来就相对比较简单。

五子棋先手胜率理论上是百分之百的,因此在发展中逐渐出现了一些禁手规则来限制先手优势。但是这些都是对于职业棋手而言,对于普通玩家来说就不需要这么多的限制,简简单单即可。这里的算法也是如此,既然是简单五子棋,因此并不考虑那么多的限制。

设计思路

既然要设计算法,我们就要挖掘五子棋背后的原理。下棋都可以归类到博弈问题。二者博弈,就是一场利益争夺战,那么最终结果就看博弈双方谁能够获得最大的利益。

我们由浅入深的分析,首先下棋分为进攻和防守模式。例如此时我方已有三颗子连线,在下一颗就四颗连线了,这是进攻;又有对方三颗子连线时,我们要去阻止对方连成四颗子,这是防守。

根据进攻和防守的思路,我们需要权衡怎么下才能获得最大利益。一个简单的方法就是将利益量化为分数,根据每个位置落子的分数高低来权衡。

如此一来建立一个公正的评分制度就很重要。根据连子的数目和连子两侧有无对方落子设立评分表如下(X为敌子,O为我子,_为空位):

布局 无子 一子 二子 三子 四子 五子
二防 XX XOX XOOX XOOOX XOOOOX XOOOOOX
一防 X_ XO_ XOO_ XOOO_ XOOOO_ XOOOOO_
无防 _ O OO OOO OOOO OOOOO
分数 无子 一子 二子 三子 四子 五子
二防 0 0 0 0 0 10000
一防 0 0 20 100 500 10000
无防 0 20 100 500 2500 10000

如果有连子数大于五子,将按五子计算。
OK,我们可以开始写程序了。

算法实现

标准的五子棋一般是15*15的格子,因此先建立棋盘,并约定1代表黑子,-1代表白子。

vector<vector<int>> topo(15, vector<int>(15, 0));

根据上面的评分表,我们来写每个位置的评分程序:

//米字型搜索
//[—, | , / , \]四个移动方向
static const int inX[] = { 1,0,1,1 };
static const int inY[] = { 0,1,1,-1 };//评分表
static const int Score[3][6] = {{ 0, 0,  0,  0,   0,10000 },//防守2子{ 0, 0, 20,100, 500,10000 },//防守1子{ 0,20,100,500,2500,10000 } //防守0子
};//topo:棋盘
//x,y:棋盘位置
//color:落子颜色(黑色:1;白色:-1)
int getScore(vector<vector<int>> topo,const int x, const int y,const int color) {//返回评分值int re = 0;//向 [—,|, /, \]四个方向搜索,对应inX,inYfor (int i = 0; i < 4; ++i) {//k记录连子两侧空位的数目(非墙,非敌方落子)int k = 0;//记录连子的数目,初始值为1因为假设在当前位置落子int count = 1;//[—,|, /, \]四个方向的正负方向for (int j = -1; j < 2; j += 2) {int dx = x + j * inX[i];int dy = y + j * inY[i];//判断是否超出棋盘边界while (dx >= 0 && dx < topo.size() &&dy >= 0 && dy < topo[0].size()) {//假如遇到颜色相同的子,count+1,反之则退出循环,并判断此时有无空位if (color*topo[dx][dy] > 0) {++count;}else {if (color*topo[dx][dy] == 0) ++k;break;}dx += j * inX[i];dy += j * inY[i];}}//假如连子大于5,使之等于5if (count > 5) count = 5;//加上该方向所得评分re += Score[k][count];}return re;
}

评分函数写好,我们开始设计AI棋手,按照之前的思路,我们只需要遍历所有空位,然后找到获取利益最大点即可。如下:

void AiChesser(int color,int &x, int &y, vector<vector<int>> topo) {int max = INT_MIN;vector<int> X;vector<int> Y;for (int i = 0; i < topo.size(); ++i) {for (int j = 0; j < topo[i].size(); ++j) {//判断是否为空位if (topo[i][j] == 0) {//进攻还是防守,寻找利益最大值int score = max(getScore(topo, i, j, color),getScore(topo, i, j, -color));//以防有多个相同的最大值if (score >= max) {if (score > max) {X.clear();Y.clear();max = score;}X.push_back(i);Y.push_back(j);}}}}//在最大值中任取一个返回,大部分情况只有一个int r = rand() % X.size();x = X[r];y = Y[r];
}

后言

当然这样程序还并不是一个可以运行的玩意,具体的UI设计就见仁见智了,这里主要只说明算法。提供easyx库设计的完整五子棋项目作为参考,附上可执行的exe文件。

这个算法其实也只达到初级棋手的水平,但足以和普通人一战了。
算法有很多地方还是值得优化的,为了代码更容易理解,许多地方简单设计了。

进阶设计

咱们的这个设计AI还是相当简单的,但是真正的高手可不会只看到眼前,他们往往下的一步是为了后面的很多步服务的。因此我们希望进一步提高我们的算法能力,就需要从后面的很多步来综合考虑,而不能只看到眼前的一步。此处就要引入极大极小值算法和alpha-beta剪枝算法,我会在以后的文章中讲解这些。

简单五子棋算法——初级篇相关推荐

  1. 夕拾算法初级篇:5)1020. 月饼(贪心)

    1020. 月饼 月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼.现给定所有种类月饼的库存量.总售价.以及市场的最大需求量,请你计算可以获得的最大收益是多少. 注意:销售时允许 ...

  2. 第18篇 Qt实现简单五子棋游戏(二)算法说明

    第18篇 Qt实现简单五子棋游戏(二)算法说明 5.算法说明 5.1.画棋盘: void drawChessboard(); 5.2.画棋子:void drawChess(); 5.3.鼠标点击响应: ...

  3. 五子棋AI算法第二篇-极大极小值搜索算法

    AI实现的基本思路-极大极小值搜索算法 五子棋AI教程第二版发布啦,地址:https://github.com/lihongxun945/myblog/labels/%E4%BA%94%E5%AD%9 ...

  4. 异形3×3魔方还原教程_【初级篇】(四)最简单的三阶魔方入门教程——中层还原...

    本系列教程适合刚刚接触魔方,又比较有好奇心,是为渴望学会还原魔方,又不想死记公式的人准备的.全部教程只使用三种公式,还原过程以理解为主,公式为辅. 第四部分 中层棱块还原 4.1 预览中层棱块还原后的 ...

  5. python五子棋算法_python实现简单五子棋游戏

    本文实例为大家分享了python实现简单五子棋游戏的具体代码,供大家参考,具体内容如下 from graphics import * from math import * import numpy a ...

  6. 通讯录排序 (20分)_算法入门篇:简单的排序算法

    作者:dorseyCh来源:http://www.imooc.com/article/264180 很久之前有过一次面试,被问到一个问题,能不能写一个冒泡排序?说实话,尽管在这之前曾经写过不少比这个更 ...

  7. Redis从入门到精通:初级篇(转)

    原文链接:http://www.cnblogs.com/xrq730/p/8890896.html,转载请注明出处,谢谢 Redis从入门到精通:初级篇 平时陆陆续续看了不少Redis的文章了,工作中 ...

  8. 小球碰壁反弹加分_用Java实现小球碰壁反弹的简单实例(算法十分简单)

    用Java实现小球碰壁反弹的简单实例(算法十分简单) 核心代码如下: if(addX){ x+=3; }else{ x-=3; } if(addY){ y+=6; }else{ y-=6; } if( ...

  9. 《挑战程序设计竞赛》--初级篇习题POJ部分【动态规划】

    关于基本的动态规划和经典的动态规划,在之前已经总结过了,可以温习一下: 传送门 这次是延续上次的<挑战程序设计竞赛>初级篇,总结部分poj上的练习题,主要是DP方面的练习题: 一.基础的动 ...

最新文章

  1. 上海大学c语言程序设计,【基础强化】2020-2021学年秋季学期程序设计C语言项目顺利开展...
  2. 仿写百度百科的目录树
  3. SSIS教程SQlServer2008R2 (5) 添加错误流重定向
  4. 玩转springboot:整合JdbcTemplate访问数据库进行操作
  5. boost::statechart模块实现使用正交状态和 state_downcast 查询正交区域的状态的测试程序
  6. 洛克人红色思考型机器人叫什么_稻船敬二新企划《红色灰烬》 依然是机器人风格...
  7. Java面试——RabbitMQ系列总结
  8. oracle的标准写法,oracle 表连接特有写法与标准写法
  9. asppython份额_为什么JAVA份额那么高,存在感却不如Python?
  10. 机器学习基础算法17-决策树-鸢尾花数据集分类及决策树深度与过拟合
  11. 对SQLite数据库操作 操作db文件
  12. MySQL的基础操作
  13. mil mm 单位换算
  14. 南京邮电大学离散数学实验一:利用真值表法求取主析取范式以及主合取范式的实现
  15. Django 对指定数据进行批量替换和删除
  16. 用Python绘制当前日期
  17. JS利用for多重循环制作9*9乘法表
  18. 如何使用 MATLAB 绘制小提琴图
  19. 怎么彻底删除手机上的微信聊天记录?百看不如一试的删除方法!
  20. 图数据库neo4j的编程语句(详解)

热门文章

  1. 8Manage|招投标流程的7个步骤
  2. 华文慕课操作系统陈向群第三章课后习题解析
  3. linux安装ftp步骤
  4. 腾讯QQ2011年2月8日被黑,黑客留下QQ号
  5. java验证码去噪_论坛灌水机(续三 -- 验证码图形去噪)
  6. 远程访问Access数据库
  7. 简述linux系统引导流程,简单介绍如何用WinGrub 引导Linux系统简述
  8. 维控协议转换网关WTGNet-LX
  9. python解三元方程组_python求解/求解三元方程组
  10. 【Python】调取tushare和joinquant的数据写入本地MySQL数据库(推荐)(技术实现过程)