象棋人工智能算法的C++实现(四)——人工智能的开端
前言:前面几篇博客详细介绍了棋盘类的封装、棋子类的封装以及各种类型的棋子的走棋算法的实现。有了前面的铺垫,就能迈出人工智能的第一步了。本系列博客还是重点介绍实现方法,很多的代码都不再过多解释了。
人机对战类:
[code]#ifndef SINGLEGAME_H #define SINGLEGAME_H #include "Board.h" class SingleGame : public Board { public: virtual void click(int id,int row,int col); //获取所有走棋路径存放到steps中 void getAllPossibleMove(QVector<Step *>& steps); //评估局面分 int calcScore(); //假装走一步 void fakeMove(Step* step); //将假装走的那一步挪回来 void unfakeMove(Step* step); //获取最佳走棋路径 Step* getBestMove(); //电脑走棋 void computerMove(); }; #endif // SINGLEGAME_H
由以上代码可以看出,人机对战类继承自棋盘类,重载了棋盘类中的click函数。其中,Step是一个QVector容器,其内部情况是这样的:
[code]#ifndef STEP_H #define STEP_H #include <QObject> class Step : public QObject { Q_OBJECT public: explicit Step(QObject *parent = 0); ~Step(); //行走棋子的id int _moveid; //杀掉棋子的id int _killid; //起始行坐标 int _rowFrom; //起始列坐标 int _colFrom; //目标位置行坐标 int _rowTo; //目标位置列坐标 int _colTo; signals: public slots: }; #endif // STEP_H
由以上代码可以看出Step类是用来存放走棋信息的。
人机对战类中重载的click函数源代码:
[code]void SingleGame::click(int id,int row,int col) { if(!this->_bRedTurn) return; Board::click(id,row,col); if(!this->_bRedTurn) { Step* step=getBestMove(); moveStone(step->_moveid,step->_killid,step->_rowTo,step->_colTo); } }
由以上代码可以看出,人类方走红棋,电脑方走黑棋。当轮到红方走棋的时候,与人人对战的时候没有区别,于是调用父类中的click函数;当轮到黑方走棋的时候,就获取对电脑最有利的走棋路径,让电脑走棋。
--------------------------------------------------------------------这里是华丽的分割线----------------------------------------------------------------------------
人工智能的实现分3步走
1.获取所有走得通的路径
上getAllPossibleMove函数的源代码:
[code]void SingleGame::getAllPossibleMove(QVector<Step *>& steps) { //遍历所有黑方棋子 for(int i=16;i<32;i++) { //如果棋子已死则直接跳过 if(_s[i]._dead) continue; //遍历所有行坐标 for(int row=0;row<=9;row++) { //遍历所有列坐标 for(int col=0;col<=8;col++) { //获取想要杀死的棋子的id int killid=this->getStoneId(row,col); //若想要杀死的棋子与行走的棋子颜色相同则跳过 if(sameColor(killid,i)) continue; //判断某一棋子能不能行走 if(canMove(i,killid,row,col)) { //将可以行走的“步”存放到steps中 saveStep(i,killid,row,col,steps); } } } } }
算法解析:遍历所有黑方的棋子,遍历到某一棋子时全方位无死角地遍历棋盘上的所有位置,把每个位置的信息都输入canMove函数,将canMove函数返回true的“步”存放到容器steps中。
2.从所有能走的路径中找到对电脑最有利的路径
上getBestMove函数的源代码:
[code]Step* SingleGame::getBestMove() { QVector<Step *> steps; //看看有哪些步骤可以走 getAllPossibleMove(steps); int maxScore=-100000; Step* ret; for(QVector<Step*>::iterator it=steps.begin();it!=steps.end();++it) { Step* step=*it; //试着走一下 fakeMove(step); //评估局面分 int score=calcScore(); //再走回来 unfakeMove(step); //取最高的分数 if(score>maxScore) { maxScore=score; ret=step; } } return ret; }
算法解析:这便是模拟人的思维的过程,从小跟爷爷下棋的时候爷爷就对我说,要走一步看三步,然而这里先实现走一步看一步。路边两个老爷爷在下棋,老爷爷虽然不会摆弄棋盘上的棋子,然而他的脑子里是在推演的,他也会权衡一下选择对自己最有利的路径走棋。fakeMove和unfakeMove便是推演的过程,假想自己走一步,评估完局面分再走回来。找到走完后局面分最高的路径作为返回值返回。
关于fakeMove函数和unfakeMove函数:
[code]void SingleGame::fakeMove(Step* step) { killStone(step->_killid); moveStone(step->_moveid,step->_killid,step->_rowTo,step->_colTo); }
[code]void SingleGame::unfakeMove(Step* step) { reliveStone(step->_killid); moveStone(step->_moveid,step->_rowFrom,step->_colFrom); }
其中killStone函数是用来杀死棋子的,relieveStone函数是用来复活棋子的。
获取最优走棋路径这一步中有个很重要的步骤就是评估局面分,上calcScore函数的源代码:
[code]int SingleGame::calcScore() { //枚举的 车=0 马=1 炮=2 兵=3 将=4 士=5 相=6 static int chessScore[]={100,50,50,20,1500,10,10}; int redTotalScore=0; int blackTotalScore=0; //计算红棋总分 for(int i=0;i<16;i++) { //如果棋子已死则跳过累加 if(_s[i]._dead) continue; redTotalScore+=chessScore[_s[i]._type]; } //计算黑棋总分 for(int i=16;i<32;i++) { //如果棋子已死则跳过累加 if(_s[i]._dead) continue; blackTotalScore+=chessScore[_s[i]._type]; } //返回黑棋总分-红棋总分 return blackTotalScore-redTotalScore; }
算法分析:先给所有棋子分配权重,根据棋子的重要程度来分配。将是最重要的棋子,因此将的权重最高,置为1500;车其次,置为100,马和炮再其次,置为50;兵再再其次,置为20;士和相最不重要,置为10。遍历红方所有的棋子,将红方活着的棋子的权重累加出一个总分;遍历黑方所有的棋子,将黑方活着的棋子的权重累加出一个总分。因为黑方是电脑,所以返回的局面分应该以黑方的角度计算,返回黑棋总分-红棋总分。
3.电脑走棋
这一部分在上面的click函数中有体现,请自行往上翻。
本片博客开始涉及到人工智能的一些基础算法,当然不是特别高级,还请勿喷。感兴趣的就可以自己动手实现一下啦!
阅读更多- 象棋人工智能算法的C++实现(五)——人机博弈的高阶算法
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 算法(C++实现)
- 最速下降优化算法的C++实现
- 迪杰斯特拉(Dijkstra)算法--(C++实现)
- 【算法】 输入n 输出一个n*n的zigzag矩阵 利用c++实现
- 组合算法 C++高效实现 (二进制辅助法)
- 算法代码实现之选择排序,C/C++ 实现
- 数字图像处理,图像锐化算法的C++实现
- 金融系统中PBOC/EMV的TLV的算法实现(含C++/C#)
- 【C++实现有序子序列合并算法】
- 算法设计--蛮力法&&分治法求最近对问题(C++实现)
- C/C++:各种基本算法实现小结(七)—— 常用算法