中国象棋项目中的极大值,极小值算法以及α-β剪枝技术技术
极大值,极小值算法
1. 问题提出
在中国象棋的人机对战模块的开发中,对于电脑如何选择下一步要走的棋时,首先很自然的想到要设立一个估值函数,然后暴力遍历所有可以移动的己方棋子以及每个棋子可以移动的目标位置,找到一个移动后估值函数值最大的移动方式。这里的估值函数最开始只是简单的为每颗棋子固定的设置不同的价值,然后用己方棋子价值之和减去对方棋子价值之和的最大值作为估值函数的返回值。这种方式效果很差,电脑在走的时候老是容易在原地打转,其实对比我们平常下棋就可以发现,我们在每走一步时,都会思考对方会怎么走,我们吃掉对方的一个棋子,会不会反而损失更多,总而言之,就是人会考虑多步,而我们只让电脑考虑了一步,那么就想到让电脑也考虑多步,可是要如何来实现呢?我们仔细分析一下,我们走棋(正常人下棋,不说高手)是要尽量可以吃掉对方的棋,然后让对方无法吃掉自己的棋,换句话说,就是我们选择时尽量得到最高的分,并且让对方得到尽量小的分,这就引出了极大值,极小值算法,在对方作出的所有对它自己价值大的选择中(意味着对己方价值小,或者为负)的选择中选择一个对自己价值最大的。
2. 代码实现
(1)需要考虑多少层
(2)递归调用终止条件
(3)求最大值(getMaxScore)和求最小值(getMinScore)函数中会调用getAllPossible函数,而这个函数会根据被谁调用内部会有不同的处理方式,因为求最大值相当于己方走一步棋,而求最小值相当于对方走一步棋(对于本项目,内部是根据该红棋走还是黑棋走返回对应的可能步骤)
(4)在最顶层之上,还应该有一个函数getBestStep开始去调用getMaxScore函数,并传入初始层级(对于本项目,这个函数会返回一个表示最佳选择的step,而不是一个分数)
(5)在本项目中,因为人走完一步后,电脑会立刻去计算它需要走的一步,如何考虑的层级较高,则会阻塞前端的渲染,解决方案为延时一点时间(使用定时器实现)再让电脑去计算(或者还可以考虑使用子线程)
//step是代表一步棋
int getMaxScore(int level)
{
//层级为0,直接计算当前分数返回
if(level == 0) return calcScore();
vector<step*> steps;//存放所有可能的走法
getAllPossibleStep(steps);//获取所有可能的走法并放到steps中
//step * res;//保存返回值
int maxScore = int(1<<31);//保存最大分数
for(auto it = steps.begin(); it != steps.end(); it++)
{
step * cur = *it;
fakeMove(step)