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

点击上方“程序人生”,选择“置顶公众号”
第一时间关注程序猿(媛)身边的故事

前言:自AlphaGo战胜世界著名九段围棋手李世石之后,我就对棋类人工智能产生了极大的兴趣,并想要自己实现象棋的人工智能。然而那个时候我还在读高二,没有这么深厚的代码基础,所以那个时候也就只能想想了。但是现在不一样了,通过学习编程,已经可以让我在棋类人工智能这个领域向前探索了。
推荐下小编的C++学习群;513801371,不管你是小白还是大牛,小编我都欢迎,不定期分享干货,包括小编自己整理的一份2019最新的C++和0基础入门教程,欢迎初学和进阶中的小伙伴。

每天晚上20:00都会开直播给大家分享C++知识和路线方法,群里会不定期更新最新的教程和学习方法(进群送2019C++学习教程),大家都是学习C++的,或是转行,或是大学生,还有工作中想提升自己能力的C++党,如果你是正在学习C++的小伙伴可以加入学习。最后祝所有程序员都能够走上人生巅峰,让代码将梦想照进现实,非常适合新手学习,有不懂的问题可以随时问我,工作不忙的时候希望可以给大家解惑

首先说明一下本系列博客描述的人工智能算法不是基于机器学习、深度学习这么高深的知识,而是一种穷举找最优走法的算法。之所以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);

下面给大家看一下棋盘类的源代码,里面是关于棋盘类的一些属性(数据成员)和需要在棋盘上进行的一些操作(函数成员),在这里我只给大家提供一个框架,各种成员函数的具体实现就要靠大家开动脑筋了。
#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;

//选中棋子的id
int _selectid;

//该不该红棋走
bool _bRedTurn;

//保存棋子的行走步骤
QVector<Step*> _steps;

//输入行列获取棋子的id
int 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;
//棋子的id
int _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++;
}
else
for(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++;
}
else
for(i=_s[moveid]._row-1;i>row;i--)
{
if(beStone(i,_s[moveid]._col)==true)
sum++;
}
return sum;
}

//两个棋子不在一条直线上
return -1;
}

  • The End -

print_r(‘点个赞吧‘);象棋人工智能算法的C++实现(一)

原文地址:https://blog.51cto.com/14209412/2354355

时间: 2024-08-30 06:56:53

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

Python神经网络算法与深度学习视频教程人工智能算法机器学习实战视频教程

38套大数据,云计算,架构,数据分析师,Hadoop,Spark,Storm,Kafka,人工智能,机器学习,深度学习,项目实战视频教程 视频课程包含: 38套大数据和人工智能精品高级课包含:大数据,云计算,架构,数据挖掘实战,实时推荐系统实战,电视收视率项目实战,实时流统计项目实战,离线电商分析项目实战,Spark大型项目实战用户分析,智能客户系统项目实战,Linux基础,Hadoop,Spark,Storm,Docker,Mapreduce,Kafka,Flume,OpenStack,Hiv

Python 人工智能算法工具包 SimpleAI

SimpleAI 是 Python 实现的人工智能算法工具包,示例代码: from simpleai.search import SearchProblem, astar GOAL = 'HELLO WORLD' class HelloProblem(SearchProblem): def actions(self, state): if len(state) < len(GOAL): return list(' ABCDEFGHIJKLMNOPQRSTUVWXYZ') else: return

微软为Bing开源搜寻人工智能算法 SPTAG

我们日常的网络活动中,有不少都是在进行搜寻,而文字搜寻之外,非文字搜寻例如声音或者图像搜寻变得越来越普及.这些功能需要人工智能辅助以分析声音或者图像内容,微软的搜寻用人工智能算法 SPTAG 最近终于开源化,让开发社群可以参与和使用这技术.微软的 Space Partition Tree And Graph(SPTAG)人工智能算法可以使开发人员能够以毫秒为单位筛选向量,也就是单词.图像像素和其他数据点的数学表示形式.微软表示,SPTAG(用 C++ 编写并用 Python 包装)是众多 Bin

马斯克:有62%的程序员认为人工智能会被武器化 #精选AR人工智能算法

当地时间 9 月 13 日,马斯克在自己的个人推特账号上转推了一篇名为<Hackers Have Already Started to Weaponize Artificial Intelligence>(编译:黑客们已经开始武器化人工智能)的文章.以下为博客节选内容. 来自安全公司 ZeroFOX 的两位数据科学家进行了一次实验,他们希望看看人类和人工智能相比,究竟谁更容易让推特用户点击恶意链接.于是,研究人员让人工智能研究社交网络用户的行为,然后设计并实施自己的网络钓鱼诱饵.从测试结果,人

象棋AI算法(二)

原文大神是用html5+js写的关于象棋AI的博客,里面重点讲了棋子的着法,自己设计的评估函数和简单的Minmax理论,没有具体的讲搜索算法,本文是对原文的学习和分析补充 一,棋子的着法com.bylaw ={}      首先创建一个数组,用于存储该棋子处于某一点时所能走到着点 (1)车: com.bylaw.c = function (x,y,map,my){ var d=[]; //左侧检索 若存在棋子且颜色不同则push过去并结束循环,否则一步步push <span style="

象棋AI算法(一)

最近想做一个象棋游戏,但是AI把我难住了.这是这几天的成果: 象棋程序通过使用"搜索"函数来寻找着法.搜索函数获得棋局信息,然后寻找对于程序一方来说最好的着法. 一,最小-最大搜索Minimax Search 首先:最小与最大是相对的,且只针对一方,AI中即为有利于AI 象棋AI中的最小最大搜索:  简单来讲就是该AI走了,穷举这个过程中对于AI来说的最佳(最大)走法对于我来说最差(最小)的走法.而这个走法就是我们所要找的AI的最佳走法. 这个过程就跟你与别人下象棋时猜测对方走法然后下

人工智能算法综述

"那一些被认作常识的东西,是不是只是时代的附属品?从整个历史的长河去看待,也许是一些莫名其妙或者残忍至极的怪事而已" ---- 默默无名 这两年因为一些爆炸式的AI应用,导致又把公众的视野转向这个方向发展,自图灵提出"图灵测试"之后,AI已经爆发了两次热潮,相应的也跌入了两次低谷,目前看应该是进入了第三次的热潮,但是之后是迎来"奇点",还是第三次低谷,尚不可知. 强人工智能(也就是通用人工智能),或者说机器的自我意识,自然是一个终极目标,但是当我

人工智能算法的提升是否与市场红利画上等号

在人工智能应用最为人熟知的两个领域就是,人脸识别和智能语音.其中人脸识别已经普及到很多应用场景,现在的智能手机都搭载了人脸识别技术,尽管存在很多方向的的漏洞但是大众对于产品还是欣然接受的.从去年的的无人超市,到现在构建智慧城市系统,接下来的人工智能推广应用该怎么走?算法的不断提升能带来多大的红利? 在宏观角度上面细小的分支将会成为人工智能的另一种个市场应用的红利大头,例如工厂设备就需要用到智能识别系统来判断设备的磨损情况,仅仅从声音上面的不同就能得出是否需要润滑油?或者车床的磨损情况怎么样,什么

Windows桌面小程序+谷歌浏览器+人工智能算法 = 100+职位一键投递

详细视频演示github开源代码网上投过简历的各位观众都知道,海投简历需要在多个招聘网站查找职位.找到合适的职位后呢,还要一个一个点击投递.对于需要大量投递简历的求职者,这一系列操作真的是非常的麻烦. 有没有什么方法可以让海投简历轻松一点呢?今天这期视频就是介绍一款我自己开发的一个windows桌面程序,专门解决海投简历操作麻烦的问题,希望它能够帮助到各位.在之后的讲解中,简称这款APP为小助手. 小助手能够解决两个问题:1.将各个网站的职位下载到本地统一管理,方便用户查询.2.可以将用户批量勾