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 }

   (二)棋局博弈树理论:

    名词:对抗性搜索(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 }

      极大值极小值搜索方案:

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

       采用递归形式,依次在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 }

            代码示例:

 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 }

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

时间: 2024-10-13 00:53:20

Qt版本中国象棋开发(四)的相关文章

Qt版本中国象棋开发(一)

开发目的:实现象棋人机对战简单AI,网络对战,移植到android中. 开发平台:windows10 + Qt5.4 for android 开发语言:C++ 开发过程:1.棋盘绘制: 方法一:重写 paintEvent(QPaintEvent *) 虚函数,调用QPainter painter(this) 画笔. 方法二:也可利用棋盘背景图片充当棋盘,背景为棋子图片的button充当棋子,有利于界面美化. 2.走棋规则: 3.人机AI,最大值,最小值算法,剪枝优化: 4.网络版: 5.andr

Qt版本中国象棋开发(三)

实现功能:棋子初始化及走棋规则 棋子类: 1 #ifndef STONE_H 2 #define STONE_H 3 4 #include <QString> 5 6 class Stone 7 { 8 public: 9 Stone(); 10 ~Stone(); 11 12 enum TYPE{JIANG, CHE, PAO, MA, BING, SHI, XIANG}; 13 14 int _row; //棋子所在行 15 int _col; //棋子所在列 16 TYPE _type;

基于QT的中国象棋

基于QT的中国象棋,可实现人人对战,人机对战,联网对战,可显示棋谱,可悔棋. 还有一些小毛病,我之后会找空把这个DEMO重新修改一下上传 链接:https://pan.baidu.com/s/1-eM0CM1KFkBTuPWpseM1bw 提取码:tumq 复制这段内容后打开百度网盘手机App,操作更方便哦 原文地址:https://www.cnblogs.com/Manual-Linux/p/10164808.html

Cocos2d-X开发中国象棋《四》设计游戏场景

设计完开始界面后就要设计游戏界面了 为了理清设计思路先看一张游戏界面效果图 游戏界面设计思路: 1.在窗口上放一张桌子 2.在桌子上放一个棋盘 3.在棋盘右边添加新局按钮,暂不实现具体的功能 4.在棋盘右边添加开始按钮,暂不实现具体的功能 5.在棋盘右边添加悔棋按钮,暂不实现具体的功能 6.在棋盘右边添加难度按钮,暂不实现具体的功能 7.在棋盘右边添加声音按钮,暂不实现具体的功能 8.在棋盘右边添加返回按钮,暂不实现具体的功能 9.在桌子右边添加一个Voice标签 10.在桌子右边添加一个Ret

Cocos2d-X开发中国象棋《六》游戏开始功能的实现

我在前面的博客Cocos2d-X开发中国象棋<四>设计游戏场景中介绍了在游戏场景上场景了一个开始按钮,并没有实现开始的功能 游戏开始功能的实现效果: 实现思路: 1.显示随机位置的棋子 2.将棋子移动到棋盘上的指定位置 具体实现方式: 首先在SceneGame类中定义一个initStone()函数用于初始化棋子 initStone()函数实现了3个功能 1.创建棋子 2.将棋子设置到随机位置 3.隐藏棋子 initStone()中的代码: //初始化32个棋子 void SceneGame::

Cocos2d-X开发中国象棋《一》

在介绍开发过程前先展示一下游戏 打开游戏后会进入一个欢迎界面 欢迎界面上有两颗棋子红色的帅和黑色的将,可以通过触摸两颗棋子进入游戏场景 当单击红棋子时,玩家持红旗 当单击黑棋时,玩家持黑棋 单击开始显示棋子 通过鼠标点击走棋 单击悔棋可以实现悔棋 单击新局后再单击开始可以实现重新下棋 单击下面的小喇叭可以实现声音的开关 吃掉对方的将后会显示游戏结果 单击游戏结果后重新开始游戏 移植到Android上的效果 开始界面 游戏界面1 游戏界面2 游戏结果界面 代码和资源下载:http://downlo

中国象棋残局库构建[抄]

残局库是经特别算法产生的特定格式的.储存各限定棋子数目的残局之所有局面及其估值的数据库文件集合.概述地说,残局数据库是储存了残局局面并经回溯分析计算过的数据库文件,它使用在棋弈程序上,当进入残局时,只要适合使用的残局数据库文件存在,程序将走得非常完美. 多数棋弈引擎并不一定要到达残局库所涵盖的局面时才使用残局库.例如,在到达如此局面之前几步,引擎计算(但还没走棋)一系列交换之后直接进入残局库里存有的局面.引擎于是搜索探查残局库并取得那个设想局面的结果.如此当然提高了棋力. 在残局库的开发方面,K

中国象棋棋子及棋盘的绘制

一.题目简介 本课程设计主要是使用Swing这个Java自带的图形开发工具实现中国象棋棋子及棋盘的绘制,并根据相应的象棋规则,可以设计棋谱,完成棋谱的保存和对已保存的棋谱的演示,方便现在爱棋人士对残局的收藏于研究,而且达到了进一步巩固课堂上所学到的知识,深刻把握Java语言的重要概念及其面向对象的特性,熟练的应用面向对象的思想和设计方法解决实际问题的能力的目的. 1.当两方有一方将(帅)被吃掉后,程序不能自动结束或提示游戏结束,但想到该程序并不是要进行两方对弈,而是要设计棋谱所以在能力实现范围内

[转载] 中国象棋软件-引擎实现(一)概述

2005年6月我系第二批科技小组的项目正式确定为实现一款中国象棋对弈软件.基本功能包括人机对战.网络对战.我负责开发人机对战的引擎部分,也就是让计算机下棋.经过了暑假整整两个月的学习与实践,我终于初步完成了程序,虽然电脑的下棋水平实在不敢恭维,但好歹也是我心血所成,所以就苟且将其命名为scCChess1.0版本,整理一下发到blog上来.(本程序在8月底就完工了,之所以现在才贴上来是因为我本想在这个学期对它进行改善,力求让电脑的下棋水平再上一个层次之后再贴出来,免得众老鸟笑话.结果这个学期实在是