• Qt版本中国象棋开发(四)


    内容:走法产生

            中国象棋基础搜索AI,

       极大值,极小值剪枝搜索,

       静态估值函数

    理论基础:

       (一)人机博弈走法产生:

        先遍历某一方的所有棋子,再遍历整个棋盘,得到每个棋子的所有走棋情况(效率不高,可以改进)

     1 void SingleGame::getAllPossibleMove(QVector<Step *> &steps)
     2 {
     3     int min, max;
     4     if(this->_bRedTurn)
     5     {
     6         min = 0, max = 16;
     7     }
     8     else
     9     {
    10         min = 16, max = 32;
    11     }
    12 
    13     for(int i=min;i<max; i++)
    14     {
    15         if(this->_s[i]._dead) continue;
    16         for(int row = 0; row<=9; ++row)
    17         {
    18             for(int col=0; col<=8; ++col)
    19             {
    20                 int killid = this->getStoneId(row, col);
    21                 if(sameColor(i, killid)) continue;
    22 
    23                 if(canMove(i, killid, row, col))
    24                 {
    25                     saveStep(i, killid, row, col, steps);
    26                 }
    27             }
    28         }
    29     }
    30 }
    View Code

       (二)棋局博弈树理论:

        名词:对抗性搜索(Adversarial Search):敌对双方交替动作的搜索

        博弈树:树的根部是棋局的初始局面,根的若干子节点是有甲的每一种可能走法生成的局面,

            这些节点的子节点则是由乙的每一种可能走法生成的局面,如此交替直到棋局结束。

        

                                                              博弈树形象表示

        

       基于博弈树的游戏:

         计甲胜为WIN,乙胜为LOST,和局为DRAW;

         轮到甲走时,甲选择通向WIN或DRAW的节点;换言之,turn 甲,选择所有子节点中最好的(对甲);

         轮到乙走时,乙选择通向LOST或DRAW的节点;turn 乙,选择所有子节点中最差的(对甲);

      (三)极大极小值算法

        在上述博弈树基础上,令甲胜的局面值为1,乙胜的局面值为-1,和局的局面值为0;

        轮到甲走时,选择子节点值最大的走法,轮到乙走时,选择子节点值最小的走法;

        中间节点的值的确定:该局面轮到甲走,选择其子节点中的最大值,

                  该局面轮到乙走,选择其子节点中的最小值。

        问题:实际的棋局不能简单的以1,-1,0三种状态表示,

           需要加入评估棋局局面分数的估值函数,配合博弈树的搜索来确定局面分数。

        实际解决方案:

           估值函数:暂时以静态估值的方式形成估值函数(评估较为粗糙),

                将棋局中的每个棋子按照重要程度赋一个值,

                估值函数通过计算一方现存棋子的总分数来确定局面优劣情况。

           代码示例:

     1 int SingleGame::score()
     2 {
     3     enum TYPE{CHE, MA, PAO, BING, JIANG, SHI, XIANG};
     4     int s[] = {52, 13, 6, 6, 100000, 6, 6, 13, 52, 22, 22, 2, 2, 2, 2, 2};
     5     //int s[] = {1000,450,501,200,15000,200,200};
     6     /*当头卒比重大*/
     7     int scoreBlack = 0;
     8     int scoreRed = 0;
     9     /*计算红方分数*/
    10     for(int i=0; i<16; ++i)
    11     {
    12         if(_s[i]._dead) continue;
    13         //scoreRed += s[_s[i]._type];
    14         scoreRed += s[i];
    15     }
    16     /*计算黑方分数*/
    17     for(int i=16; i<32; ++i)
    18     {
    19         if(_s[i]._dead) continue;
    20         //scoreBlack += s[_s[i]._type];
    21         scoreBlack += s[i-16];
    22     }
    23     return scoreBlack - scoreRed;
    24 }
    View Code

          极大值极小值搜索方案:

           深度优先搜索,优点是不必在内存中生成整个博弈树,可以将搜索过的部分从内存中去除,

           采用递归形式,依次在min(int level,int curMin),max(int level,int curMax)之间递归调用,

           剪枝以去除不必要的步数,在求极大值时,若下一步的值小于当前极大值,直接删除这一步,不予考虑,

                       在求极小值时,若下一步的值大于当前极小值,直接删除这一步,不予考虑。

           在所有子节点中选出值最大的走法,就是电脑的最佳走法。

           代码示例:

     1 int SingleGame::getMinScore(int level, int curMin)
     2 {
     3     if(level == 0)
     4         return score();
     5 
     6     QVector<Step*> steps;
     7     getAllPossibleMove(steps);
     8     int minInAllMaxScore = 300000;
     9 
    10     while(steps.count())
    11     {
    12         Step* step = steps.last();
    13         steps.removeLast();
    14 
    15         fakeMove(step);
    16         int maxScore = getMaxScore(level-1, minInAllMaxScore);
    17         unfakeMove(step);
    18         delete step;
    19 
    20         if(maxScore <= curMin)
    21         {
    22             while(steps.count())
    23             {
    24                 Step* step = steps.last();
    25                 steps.removeLast();
    26                 delete step;
    27             }
    28             return maxScore;
    29         }
    30 
    31         if(maxScore < minInAllMaxScore)
    32         {
    33             minInAllMaxScore = maxScore;
    34         }
    35     }
    36     return minInAllMaxScore;
    37 }
    38 int SingleGame::getMaxScore(int level, int curMax)
    39 {
    40     if(level == 0)
    41         return score();
    42 
    43     QVector<Step*> steps;
    44     getAllPossibleMove(steps);
    45     int maxInAllMinScore = -300000;
    46 
    47     while(steps.count())
    48     {
    49         Step* step = steps.last();
    50         steps.removeLast();
    51 
    52         fakeMove(step);
    53         int minScore = getMinScore(level-1, maxInAllMinScore);
    54         unfakeMove(step);
    55         delete step;
    56 
    57         if(minScore >= curMax)
    58         {
    59             while(steps.count())
    60             {
    61                 Step* step = steps.last();
    62                 steps.removeLast();
    63                 delete step;
    64             }
    65             return minScore;
    66         }
    67         if(minScore > maxInAllMinScore)
    68         {
    69             maxInAllMinScore = minScore;
    70         }
    71 
    72 
    73     }
    74     return maxInAllMinScore;
    75 }
    View Code

                代码示例:

     1 Step* SingleGame::getBestMove()
     2 {
     3     Step* ret = NULL;
     4     QVector<Step*> steps;
     5     getAllPossibleMove(steps);
     6     int maxInAllMinScore = -300000;
     7 
     8     while(steps.count())
     9     {
    10         Step* step = steps.last();
    11         steps.removeLast();
    12 
    13         fakeMove(step);
    14         int minScore = getMinScore(this->_level-1, maxInAllMinScore);
    15         unfakeMove(step);
    16 
    17         if(minScore > maxInAllMinScore)
    18         {
    19             if(ret) delete ret;
    20 
    21             ret = step;
    22             maxInAllMinScore = minScore;
    23         }
    24         else
    25         {
    26             delete step;
    27         }
    28     }
    29     return ret;
    30 }
    View Code

        一个简单的象棋AI,还有诸多优化之处,目前搜索深度最大为4,与初级玩家对弈输多胜少。

  • 相关阅读:
    关于产品
    Windows服务 + Quartz.NET
    C#
    C#
    URL
    前端生态系统总结
    字符串相似度
    Process Explore & Windbg
    webpack
    JS
  • 原文地址:https://www.cnblogs.com/weiyikang/p/6389501.html
Copyright © 2020-2023  润新知