01 - 极大极小值算法
上一期博客介绍了最为简单的人机博弈算法,包括获取所有合法路径,简单的估值以及电脑走棋,本期博客在介绍估值算法上增加极大极小值算法(Minmax算法),让电脑走棋更加智能化。
极大极小值算法是一种找出失败的最大可能性中的最小值的算法,即最小化对手的最大收益。举个栗子,电脑为A,人类为B,A在走棋之前需要考虑A走了某一步之后,看看B有哪些走法,B又不傻,所以B肯定是要选择让A得分最小的走法走棋,而A就是在A的所有走法中选择B给出让A得分最小的走法中得分最多的走法。听起来比较抽象,试着多读几遍就理解了。
电脑导入极大极小值算法分以下3步:
(1)在当前局面下获取电脑所有走棋路径,并试着走一下;
(2)在电脑试着走完一步基础上获取人类所有走棋路径,并以人类的视角试着走一下,然后评估局面分(局面分是以电脑角度计算的,即电脑总分 - 人类总分),遍历完人类所有走棋路径后返回这些局面中的最小值(对电脑最不利而对人类最优利的情况);
(3)在上一步返回的局面分的最小值中,找到最大值,并且锁定与该最大值对应的走棋路径作为“步”返回值返回。
02 - 电脑和人类所有走棋路径
实现算法第一步是要获取电脑和人类的所有走棋路径,所以对getAllPossibleMove函数稍微做出以下修改:
/**
*
* @brief : 获取所有棋子可行走的步骤
*
* @param : steps : 保存移动棋子信息的属性(原坐标、目标坐标、ID、目标ID)
*
* @return: 无
*
**/
void ChessArea::getAllPossibleMove(QVector<Step *> &steps)
{
int min = 16, max = 32;
if(this->bRedTurn)
{
min = 0;
max = 16;
}
//遍历所有黑方棋子
for(int i = min; i < max; i++)
{
//如果棋子已死则直接跳过
if(myChess[i].isDead)
continue;
// 遍历所有行坐标
for(int x=0; x<9; x++)
{
// 遍历所有列坐标
for(int y=0; y<10; y++)
{
//获取想要杀死的棋子的id
int killid = this->getChessID(x, y);
//若想要杀死的棋子与行走的棋子颜色相同则跳过
if(sameColor(i, killid))
continue;
//判断某一棋子能不能行走
if(canMove(i, killid, x, y))