前言:自AlphaGo战胜世界著名九段围棋手李世石之后,我就对棋类人工智能产生了极大的兴趣,并想要自己实现象棋的人工智能。然而那个时候我还在读高二,没有这么深厚的代码基础,所以那个时候也就只能想想了。但是现在不一样了,通过学习编程,已经可以让我在棋类人工智能这个领域向前探索了。

首先说明一下本系列博客描述的人工智能算法不是基于机器学习、深度学习这么高深的知识,而是一种穷举找最优走法的算法。之所以AlphaGo不能使用这种算法战胜李世石,是因为围棋棋局局势的判断是极为复杂的,想要穷举所有的情况,全世界所有的计算机一起运行一百万年也无法找到最优走法。所以DeepMind团队的大佬就想出了另一种解决方案就是让AlphaGo自己学习高水平棋手间的对局,从而提升AlphaGo的棋力。然而象棋的棋局判断还是比较容易的,杀掉对面的老将就可以获胜,杀掉对面的车马炮等棋子就可以提高自己的胜率/降低对方的胜率。具体的算法在之后的篇章详细讲解。

实现本系列博客中算法的编程工具是Qt5.5.1。

既然实现象棋人工智能的算法的本质是穷举,那么就要找到所有的通路,所谓的通路就是能够走棋的那些“路”们,走不通的那些“路”就要直接被pass掉。

1.先把棋盘抽象出来,象棋棋盘有10行9列,行标设为0~9,列标设为0~8。以左上角的坐标为(0,0),假设初始时上方为红棋,下方为黑棋。则初始时所有棋子的坐标为:

车1(红方):(0,0);车2(红方):(0,8);

马1(红方):(0,1);马2(红方):(0,7);

相1(红方):(0,2);相2(红方):(0,6);

士1(红方):(0,3);士2(红方):(0,5);

将(红方):(0,4);

炮1(红方):(2,1);炮2(红方):(2,7);

兵1(红方):(3,0);兵2(红方):(3,2);兵3(红方):(0,4);兵4(红方):(0,6);兵5(红方):(0,8);

注:红方的棋子行列坐标对应黑方棋子的行列坐标的关系为:红方行号+黑方行号=9;红方列号+黑方列号=8。

车1(黑方):(9,8);车2(黑方):(9,0);

马1(黑方):(9,7);马2(黑方):(9,1);

相1(黑方):(9,6);相2(黑方):(9,2);

士1(黑方):(9,5);士2(黑方):(9,3);

将(黑方):(9,4);

炮1(黑方):(7,7);炮2(黑方):(7,1);

兵1(黑方):(6,8);兵2(黑方):(6,6);兵3(黑方):(6,4);兵4(黑方):(6,2);兵5(黑方):(6,0);

下面给大家看一下棋盘类的源代码,里面是关于棋盘类的一些属性(数据成员)和需要在棋盘上进行的一些操作(函数成员),在这里我只给大家提供一个框架,各种成员函数的具体实现就要靠大家开动脑筋了。如果大家在这期间遇到什么问题,尽量要自己解决,如果实在解决不了,给大家提供一下我的邮箱:freedom11235@126.com。

#ifndef BOARD_H
#define BOARD_H#include <QFrame>
#include "Stone.h"
#include "Step.h"
#include <QVector>
#include <QMouseEvent>class Board : public QWidget
{Q_OBJECT
public:explicit Board(QWidget *parent = 0);//32颗棋子Stone _s[32];//棋子的像素半径int _r;//选中棋子的idint _selectid;//该不该红棋走bool _bRedTurn;//保存棋子的行走步骤QVector<Step*> _steps;//输入行列获取棋子的idint getStoneId(int row,int col);//计算即将行走的棋子与某一坐标之间有几颗棋子int num_of_Stone(int moveid,int row,int col);//输入行列坐标判断该坐标上有没有棋子bool beStone(int row,int col);bool canSelect(int id);//最基本的能不能走的判断判断bool canMove(int moveid,int row,int col,int killid);//判断将能不能走bool canMoveJIANG(int moveid,int row,int col,int killid);//判断士能不能走bool canMoveSHI(int moveid,int row,int col,int killid);//判断象能不能走bool canMoveXIANG(int moveid,int row,int col,int killid);//判断车能不能走bool canMoveCHE(int moveid,int row,int col,int killid);//判断马能不能走bool canMoveMA(int moveid,int row,int col,int killid);//判断炮能不能走bool canMovePAO(int moveid,int row,int col,int killid);//判断兵能不能走bool canMoveBING(int moveid,int row,int col,int killid);//尝试函数void trySelectStone(int id);void tryMoveStone(int killid, int row, int col);//判断两个棋子是否是同一方的bool sameColor(int id1, int id2);//走棋函数极其重载void moveStone(int moveid, int killid, int row, int col);void moveStone(int moveid, int row, int col);//杀死棋子的函数void killStone(int id);//复活棋子的函数void reliveStone(int id);void saveStep(int moveid, int killid, int row, int col, QVector<Step*>& steps);//与鼠标点击有关的函数void mouseReleaseEvent(QMouseEvent *);void click(QPoint pt);virtual void click(int id,int row,int col);//获取鼠标点击位置的行列坐标bool getRowCol(QPoint pt,int &row,int &col);//与显示到窗口中有关的函数void drawStone(QPainter& painter,int id);void paintEvent(QPaintEvent *);//输入行列坐标 返回像素坐标QPoint center(int row,int col);//输入棋子的id 返回像素坐标QPoint center(int id);
signals:public slots:
};#endif // BOARD_H

2.再把棋子抽象出来。每个棋子都有一个id,初始时共有32枚棋子,id从0到31;棋子所具有的属性除了id还有所处的行列位置,棋子的类型(车马炮将士相兵),棋子的颜色(红/黑),棋子是否还存活着。id置为int型;棋子类型置为枚举类型enum TYPE{JIANG,CHE,PAO,MA,BING,SHI,XIANG};棋子的颜色置为bool型_red,红棋为true,黑棋为false;棋子是否还存活置为bool型,活着为true,被吃掉为false。

#ifndef STONE_H
#define STONE_H#include <QString>
class Stone
{
public:Stone();//枚举棋子的所有类型enum TYPE{JIANG,CHE,PAO,MA,BING,SHI,XIANG};//棋子所处的行int _row;//棋子所处的列int _col;//棋子的idint _id;//棋子是否已死bool _dead;//棋子是否为红子bool _red;//棋子类型TYPE _type;//初始化棋子void init(int id);//获取棋子的类型名QString getText();
};#endif // STONE_H

3.按照象棋的规则实现每个棋子的走法的前期函数铺垫。这一部分是后期人工智能算法的基础,因为后期要将所有能走的通的“路”保存在一个C++容器(类似于C语言中的数组)里。

(1)确定某个行列位置上是否存在棋子。

这个函数在后面具体棋子的走法算法中应用的非常广泛。例如走马的时候需要判断是否别了马腿,也就是需要判定想要移动的马在要去的方向的正前方的位置是否有别的棋子挡住,即判断该位置上是否存在棋子;再例如如果出现了“对将”的情况,需要判断红将和黑将之间与其在同一直线上的所有位置上是否存在棋子,若所有位置都不存在棋子则两个将可以对吃。

其实现的原理很简单,即输入一个行列坐标后遍历所有存活的棋子的行列坐标看一下有没有棋子与之完全吻合,若存在这样的棋子,则表示该行列坐标上存在棋子。

/*确定某个行列位置上是否有棋子*/
bool Board::beStone(int row,int col)
{for(int i=0;i<32;i++)if(_s[i]._row==row&&_s[i]._col==col&&!_s[i]._dead)return true;return false;
}

(2)计算某一棋子与某一行列坐标之间有几颗棋子。

这个函数主要应用在“对将”以及车和炮的走棋算法上。例如炮如果想要隔着炮架吃掉对方的棋子就需要保证该炮与想要吃掉的对方的棋子之间有且仅有一个棋子;再例如车想要走棋到某一行列坐标必须保证该车与想要走到的位置之间没有棋子。

有了(1)的铺垫,本函数的实现就变得容易了。首先需要判定一下即将行走的棋子的位置与目标位置在不在同一行(列)上。如果不在同一行(列)上则直接返回-1;如果在则可以遍历一整行(列)并调用(1)所介绍的函数beStone来统计即将行走的棋子与目标位置之间棋子的个数。

//计算即将行走的棋子与某一坐标之间有几颗棋子 默认返回值为-1
int Board::num_of_Stone(int moveid,int row,int col)
{int i;int sum=0;if(_s[moveid]._row==row){if(col-_s[moveid]._col>0)for(i=_s[moveid]._col+1;i<col;i++){if(beStone(_s[moveid]._row,i)==true)sum++;}elsefor(i=_s[moveid]._col-1;i>col;i--){if(beStone(_s[moveid]._row,i)==true)sum++;}return sum;}else if(_s[moveid]._col==col){if(row-_s[moveid]._row>0)for(i=_s[moveid]._row+1;i<row;i++){if(beStone(i,_s[moveid]._col)==true)sum++;}elsefor(i=_s[moveid]._row-1;i>row;i--){if(beStone(i,_s[moveid]._col)==true)sum++;}return sum;}//两个棋子不在一条直线上return -1;
}

这个项目我会连载,后期各种算法的实现敬请期待!

欢迎大家关注/订阅我的微信公众号Code Art Online,我会在我的公众号分享个人见闻,发现生活趣味;这里不仅有0和1,还有是诗和远方↓↓↓

象棋人工智能算法的C++实现(一)相关推荐

  1. 象棋人工智能算法的C++实现(二)

    欢迎大家关注/订阅我的微信公众号Code Art Online,我会在我的公众号分享个人见闻,发现生活趣味:这里不仅有0和1,还有是诗和远方↓↓↓ 前言:在看完上一期博客后,是不是对这个项目感到有点小 ...

  2. 象棋人工智能算法的C++实现(四)——人工智能的开端

    欢迎大家关注/订阅我的微信公众号Code Art Online,我会在我的公众号分享个人见闻,发现生活趣味:这里不仅有0和1,还有是诗和远方↓↓↓ 前言:前面几篇博客详细介绍了棋盘类的封装.棋子类的封 ...

  3. 象棋人工智能算法的C++实现(三)——注重功能分区!!!

    欢迎大家关注/订阅我的微信公众号Code Art Online,我会在我的公众号分享个人见闻,发现生活趣味:这里不仅有0和1,还有是诗和远方↓↓↓ 前言:上一期博客我们介绍了相对简单的士.兵.相.马的 ...

  4. 智源人工智能算法大赛开锣,百万奖金激励 AI 算法创新

    智源人工智能算法大赛现已正式启动!本次比赛由北京智源人工智能研究院主办,清华大学.北京大学.中科院计算所.旷视.知乎等协办,总奖金超过 100 万元,旨在以全球领先的科研数据集与算法竞赛为平台,选拔培 ...

  5. 开源人工智能算法一种新颖的超像素采样网络深层特征来估计任务特定的超像素

    开源人工智能算法一种新颖的超像素采样网络深层特征来估计任务特定的超像素摘要: 超像素提供图像数据的有效低/中级表示,这极大地减少了后续视觉任务的图像基元的数量. 现有的超像素算法无法区分,因此难以集成 ...

  6. 重磅MIT开源人工智能算法评估和理解对抗Logit配对的稳健性

    重磅MIT开源人工智能算法评估和理解对抗Logit配对的稳健性摘要:我们评估了对抗性Logit Pairing的稳健性,这是最近针对广告范例提出的防御措施. 我们发现,使用Adversarial Lo ...

  7. 标准发布丨央行发布《人工智能算法金融应用评价规范》

    2021-05-11 11:12:26 来源:中国人民银行 为全面提升人工智能技术在金融领域应用和管理水平,推动金融与科技深度融合协调发展,中国人民银行制定了<人工智能算法金融应用评价规范> ...

  8. 深思:外卖背后的人工智能算法揭秘

    知识积累带来规模递增,规模递增引发市场集中. 当一个行业可以以"流水线"的形式固定下来后,这个行业中,人的价值就被越来越弱化与微不足道,从身体.动作.时间.精力等,都被重复的机器与 ...

  9. 人工智能算法的可解释性方法研究

    来源:数学与人工智能 摘要 以深度学习为代表的人工智能技术在信息领域的应用,极大地提高了信息的利用效率和挖掘价值,深刻的影响了各领域的业务形态,同时也引发了监管部门和用户对这一新技术运用中出现的 &q ...

最新文章

  1. new File(String Path)加载资源问题
  2. RHEL7 yum安装配置LAMP(Apache+PHP+MySql)服务器
  3. Normal-Inverse Gamma Mixture简介
  4. EXE和SYS通信(ReadFile WriteFile DO_BUFFERED_IO) 缓冲区方式
  5. java 简单获取Excel表格内容(初学者)
  6. Android开发学习之路--网络编程之初体验
  7. GitHub for windows使用备忘录
  8. MySQL实现类似Oracle的序列
  9. python学习第十六天 --继承进阶篇
  10. windows系统: 解决ie谷歌浏览器证书错误.2021-05-27
  11. Am2910的指令扩展
  12. 梦飞苍穹c语言答案,梦飞仙途-楔子一  决战苍穹之巅-汤圆创作
  13. 使用VMware安装CentOS
  14. java毕业设计拾忆鲜花销售系统mybatis+源码+调试部署+系统+数据库+lw
  15. java 设计模式
  16. 史上最全 | 计算机视觉2D/3D标注工具汇总!
  17. 点击网页分享按钮,触发微信分享功能
  18. 食用油详细 制造工艺、等级划分、国家标准号和注意事项
  19. java音频源码,Android Java实时音频SDK示例源码下载 - 开发者中心 - ZEGO即构科技
  20. 生物医药实验室安全知识202203第四次作业答案(2022.11.11)

热门文章

  1. 无法启动 parallels desktop 缺少插件_手机资讯:iOS7.1.2越狱插件推荐:CCSliders亮度滑动条变万能神器...
  2. JavaScript+css实现的响应式登录注册页面web前端html源码
  3. java新建一个女朋友_java创建一个女朋友类(对象啥的new一个就是)==建造者模式,一键重写...
  4. 计算机组成原理学习笔记第4章 4.12——虚拟存储器
  5. openssl之EVP实现哈希(md5,sha256,sm3)
  6. vue组件导入的方式
  7. Bean Validation 校验实践
  8. 案例演示 | 基于Motor-CAD日产聆风汽车电机的多物理场仿真
  9. php mysql 预处理_PHP MySQL 预处理语句
  10. [zotero] PDF translate 有道智云API接入