α-β剪枝实现的一字棋实验报告
实验二:利用α-β搜索过程的博弈树搜索算法编写一字棋游戏

实验二:利用α-β搜索过程的博弈树搜索算法编写一字棋游戏(3学时)一、实验目的与要求(1)了解极大极小算法的原理和使用方法,并学会用α-β剪枝来提高算法的效率。
(2)使用C语言平台,编写一个智能井字棋游戏。
(3)结合极大极小算法的使用方法和α-β剪枝,让机器与人对弈时不但有智能的特征,而且计算的效率也比较高。
二、实验原理一字棋游戏是一个流传已久的传统游戏。
游戏由两个人轮流来下,分别用“X”和“O”来代替自身的棋子。
棋盘分9个格,双方可以在轮到自己下的时候,可以用棋子占领其中一个空的格子。
如果双方中有一方的棋子可以连成一条直线,则这一方判胜,对方判负。
当所有的格子都被占领,但双方都无法使棋子连成一条直线的话,则判和棋。
这是一个智能型的一字棋游戏,机器可以模拟人与用户对弈。
当轮到机器来下的时候,机器会根据当前棋局的形势,利用极大极小算法算出一个评价值,判断如何下才对自身最有利,同时也是对方来说对不利的,然后下在评价值最高的地方。
另外利用α-β剪枝,使机器在搜索评价值的时候不用扩展不必要的结点,从而提高机器计算的效率。
在用户界面方法,用一个3×3的井字格来显示用户与机器下的结果。
当要求用户输入数据的时候会有提示信息。
用户在下的过程中可以中途按下“0”退出。
当用户与计算机分出了胜负后,机器会显示出比赛的结果,并按任意键退出。
如果用户在下棋的过程中,输入的是非法字符,机器不会做出反应。
三、实验步骤和过程1.α-β搜索过程在极小极大搜索方法中,由于要先生成指定深度以内的所有节点,其节点数将随着搜索深度的增加承指数增长。
这极大地限制了极小极大搜索方法的使用。
能否在搜索深度不变的情况下,利用已有的搜索信息减少生成的节点数呢?设某博弈问题如下图所示,应用极小极大方法进行搜索MINIMAX过程是把搜索树的生成和格局估值这两个过程分开来进行,即先生成全部搜索树,然后再进行端节点静态估值和倒推值计算,这显然会导致低效率。
α-β剪枝算法例题

α-β剪枝算法例题α-β剪枝算法是一种用于优化博弈树搜索的算法,它通过剪去不必要的搜索分支来减少搜索空间,从而提高搜索效率。
下面我将以一个简单的例题来说明α-β剪枝算法的应用。
假设我们有一个简化的棋盘游戏,双方轮流在棋盘上放置棋子,每个棋子的位置可以用一个坐标表示。
游戏的目标是找到双方都无法再放置棋子的最佳位置。
我们可以用一个博弈树来表示游戏的状态和可能的走法。
每个节点表示游戏的一个状态,边表示一次棋子的放置。
叶子节点表示游戏结束的状态,双方都无法再放置棋子。
我们的目标是找到一个最佳的叶子节点。
现在,我们来看一个简化的博弈树:A./ | \。
B C D./|\ / \。
E F G H I.在这个博弈树中,A是根节点,B、C、D是A的子节点,E、F、G是B的子节点,H和I是D的子节点。
每个节点都有一个评估值,表示当前状态的好坏。
我们可以使用α-β剪枝算法来搜索博弈树,找到最佳的叶子节点。
算法的基本思想是,在搜索过程中维护两个值,α和β。
α表示当前玩家的最好选择,β表示对手的最好选择。
在搜索过程中,我们从根节点开始,递归地向下搜索子节点。
对于每个节点,我们根据当前玩家是最大化还是最小化来更新α和β的值。
如果β小于等于α,表示对手已经找到了一个更好的选择,我们可以剪掉当前节点的搜索分支,不再继续搜索。
具体地,我们可以使用以下伪代码表示α-β剪枝算法:function alphabeta(node, depth, α, β,maximizingPlayer):if depth = 0 or node is a terminal node:return the heuristic value of node.if maximizingPlayer:value = -∞。
for each child of node:value = max(value, alphabeta(child, depth 1, α, β, FALSE))。
4.6 α–β剪枝技术

5
3
3
Develop Way
9
Example 2
2 2 ≤
≥2 2
≥7
β剪枝
2
≤1
7
α剪枝
2
8
1
15
7
10
Example 3-1 一字棋剪 枝
α
α ≥1
剪枝
S0
β≤ -1
S3
β≤ -2
S1 S4 S5
S2
order of develop
11
Example 3-2 一字棋剪枝
α
α ≥ -1
剪枝
β
Q: if α ≥β , is it necessary to develop other children of the ‘and node’?
6
α 剪枝
(1)或节点下确界α=3 (2)或节点子节点上确界β =2,即α ≥β
≥3
3
≤2 3
2
3 5
扩展顺序
7
4) β剪枝方法
≤β
对于一个与节点,
S0
1
S3
S1
β≤ -1
β≤ 1
S2
S4
S5
order of develop
12
小结
• • • • 博弈 —— 研究对象 博弈树 —— 表示对象 极大极小 —— 问题求节 α –β 剪枝 —— 求解优化
13
Home work
• 1. 一字棋剪枝 • 扩展顺序 S2,S1,S3, 说明一字棋剪枝过程 • 2.极小极大分析法,计算其倒推值,说明计 算其倒推值过程
4.6α –β 剪枝技术
4.6.1引入原因
极小极大分析法,实际是先生成一棵博弈树,然后再计 算其倒推值,这样做效率较低。
博弈树搜索算法实验报告

一、实验目的本次实验旨在理解和掌握博弈树搜索算法的基本原理和应用,通过实际编程实现一个简单的井字棋游戏,并运用极大极小搜索和α-β剪枝算法优化搜索过程,提高算法效率。
二、实验原理1. 博弈树:博弈树是表示棋局所有可能变化的一种树状结构。
每一层代表棋局的一个状态,每个节点代表一个具体的棋盘布局。
从一个初始状态开始,通过一系列的走法,可以生成一棵完整的博弈树。
2. 极大极小搜索:极大极小搜索是一种基于博弈树的搜索算法,用于求解零和博弈问题。
在井字棋游戏中,一方为MAX(最大化自己的收益),另一方为MIN(最小化自己的收益)。
MAX的目的是争取获胜,而MIN的目的是避免失败。
3. α-β剪枝:α-β剪枝是一种剪枝技术,用于减少搜索树中需要搜索的节点数量。
在搜索过程中,如果发现当前节点的值小于α,则可以剪掉其右子树;如果发现当前节点的值大于β,则可以剪掉其左子树。
三、实验内容1. 游戏规则:井字棋的棋盘是一个3x3的格子,双方轮流在空格中放置自己的棋子(MAX用“O”,MIN用“X”)。
首先在横线、竖线或对角线上形成三个连续棋子的玩家获胜。
2. 编程实现:- 定义棋盘数据结构,包括棋盘大小、棋子状态等。
- 实现棋子的放置和移动功能。
- 实现检查胜负的功能。
- 实现极大极小搜索和α-β剪枝算法。
- 实现人机对战功能。
3. 算法优化:- 采用启发式搜索,根据当前棋盘状态评估双方的胜率。
- 优化搜索顺序,优先搜索对当前局势更有利的节点。
四、实验结果与分析1. 实验结果:通过实验,成功实现了井字棋游戏,并实现了人机对战功能。
在搜索过程中,α-β剪枝算法有效减少了搜索节点数量,提高了搜索效率。
2. 结果分析:- 极大极小搜索和α-β剪枝算法能够有效地解决井字棋问题,实现人机对战。
- 启发式搜索和搜索顺序优化能够进一步提高搜索效率。
- 博弈树搜索算法在解决类似问题(如五子棋、国际象棋等)中具有广泛的应用前景。
五、实验总结1. 收获:通过本次实验,掌握了博弈树搜索算法的基本原理和应用,学会了极大极小搜索和α-β剪枝算法,并成功地实现了井字棋游戏。
人工智能五子棋实验报告

题目:智能五子棋游戏一、实验目的理解和掌握博弈树的启发式搜索过程和α-β减枝技术,能够用某种程序语言开发一个五子棋博弈游戏。
二、实验要求(1)设计一个15行15列棋盘,要求自行给出估价函数,按极大极小搜索方法,并采用α-β减枝技术。
(2)采用人机对弈方式,对弈双方设置不用颜色的棋子,一方走完后,等待对方走步,对弈过程的每个棋局都在屏幕上显示出来。
当某一方在横、竖或斜方向上先有5个棋子连成一线时,该方为赢。
(3)提交一篇实验论文,以及完整的软件(包括源程序和可可执行程序)和相关文档。
三、实验原理①估价函数的设计:下子后,求在该点的所有8个方向上4格之内的所有的没有阻隔的白子的和加上没有阻隔的黑子的数目之和,和为估价函数的值。
直观来说就是,如果在该点下子后连成同颜色的棋子越多,该点的估价值越大,同时阻挡另一种颜色的棋子越多,估价值也越大。
②判断是否有一方胜出:设计is_win函数,在每一次下子后检查是否是终局(一方胜出或者棋盘下满和局)。
对于棋盘上每一个已经下了棋子的点,检查其4个方向上是否有连续5颗同颜色的棋子,若有,则有一方胜出。
③寻找候选点,用于建立博弈树:对于棋盘上每一个还没有下子的点,测试其附近8个点是否已经下了棋子,若有,把该点加入候选点。
④搜寻最佳着点:根据候选点建立3层的博弈树,再利用估价函数对节点进行比较,得出最佳着点。
四、代码人主要代码public void refreshMax(int n){switch(n){case 1:{ //更新预测棋盘1最大值及其坐标maxValue1=0;number1=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard1[i][j]>maxValue1){maxX1.clear();maxY1.clear();maxX1.add(i);maxY1.add(j);number1=1;}else if(preBoard1[i][j]==maxValue1){maxX1.add(i);maxY1.add(j);number1++;}}}break;}case 2:{ //更新预测棋盘2最大值及其坐标maxValue2=0;number2=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard2[i][j]>maxValue2){maxX2.clear();maxY2.clear();maxX2.add(i);maxY2.add(j);number2=1;}else if(preBoard2[i][j]==maxValue2){maxX2.add(i);maxY2.add(j);number2++;}}}break;}case 3:{ //更新预测棋盘3最大值及其坐标maxValue3=0;number3=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard3[i][j]>maxValue3){maxX3.clear();maxY3.clear();maxX3.add(i);maxY3.add(j);number3=1;}else if(preBoard3[i][j]==maxValue3){maxX3.add(i);maxY3.add(j);number3++;}}}break;}case 4:{ //更新预测棋盘4最大值及其坐标maxValue4=0;number4=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard4[i][j]>maxValue4){maxX4.clear();maxY4.clear();maxX4.add(i);maxY4.add(j);number4=1;}else if(preBoard4[i][j]==maxValue4){maxX4.add(i);maxY4.add(j);number4++;}}}break;}case 5:{ //更新预测棋盘5最大值及其坐标maxValue5=0;number5=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard5[i][j]>maxValue5){maxX5.clear();maxY5.clear();maxX5.add(i);maxY5.add(j);number5=1;}else if(preBoard5[i][j]==maxValue5){maxX5.add(i);maxY5.add(j);number5++;}}}break;}case 6:{ //更新预测棋盘6最大值及其坐标maxValue6=0;number6=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard6[i][j]>maxValue6){maxX6.clear();maxY6.clear();maxX6.add(i);maxY6.add(j);number6=1;}else if(preBoard6[i][j]==maxValue6){maxX6.add(i);maxY6.add(j);number6++;}}}break;}case 7:{ //更新预测棋盘7最大值及其坐标maxValue7=0;number7=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard7[i][j]>maxValue7){maxX7.clear();maxY7.clear();maxX7.add(i);maxY7.add(j);number7=1;}else if(preBoard7[i][j]==maxValue7){maxX7.add(i);maxY7.add(j);number7++;}}}break;}}}AI主要代码public void refreshMax(int n){switch(n){maxValue1=0;number1=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard1[i][j]>maxValue1){maxValue1=preBoard1[i][j];maxX1.clear();maxY1.clear();maxX1.add(i);maxY1.add(j);number1=1;}else if(preBoard1[i][j]==maxValue1){maxX1.add(i);maxY1.add(j);number1++;}}}break;}maxValue2=0;number2=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard2[i][j]>maxValue2){maxValue2=preBoard2[i][j];maxX2.clear();maxY2.clear();maxX2.add(i);maxY2.add(j);number2=1;}else if(preBoard2[i][j]==maxValue2){maxX2.add(i);maxY2.add(j);number2++;}}}break;}maxValue3=0;number3=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard3[i][j]>maxValue3){maxValue3=preBoard3[i][j];maxX3.clear();maxY3.clear();maxX3.add(i);maxY3.add(j);number3=1;}else if(preBoard3[i][j]==maxValue3){maxX3.add(i);maxY3.add(j);number3++;}}}break;}maxValue4=0;number4=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard4[i][j]>maxValue4){maxValue4=preBoard4[i][j];maxX4.clear();maxY4.clear();maxX4.add(i);maxY4.add(j);number4=1;}else if(preBoard4[i][j]==maxValue4){maxX4.add(i);maxY4.add(j);number4++;}}}break;}maxValue5=0;number5=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard5[i][j]>maxValue5){maxValue5=preBoard5[i][j];maxX5.clear();maxY5.clear();maxX5.add(i);maxY5.add(j);number5=1;}else if(preBoard5[i][j]==maxValue5){maxX5.add(i);maxY5.add(j);number5++;}}}break;}maxValue6=0;number6=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard6[i][j]>maxValue6){maxValue6=preBoard6[i][j];maxX6.clear();maxY6.clear();maxX6.add(i);maxY6.add(j);number6=1;}else if(preBoard6[i][j]==maxValue6){maxX6.add(i);maxY6.add(j);number6++;}}}break;}maxValue7=0;number7=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){if(preBoard7[i][j]>maxValue7){maxValue7=preBoard7[i][j];maxX7.clear();maxY7.clear();maxX7.add(i);maxY7.add(j);number7=1;}else if(preBoard7[i][j]==maxValue7){maxX7.add(i);maxY7.add(j);number7++;}}}break;}}}五、感想通过这个试验,我对估价函数,极大极小搜索方法,α-β减枝技术有了更全面的认识,对它们的运用也更加熟练。
alphabeta剪枝例题

alphabeta剪枝例题Alpha-Beta剪枝算法是一种在搜索博弈树的过程中,通过维护两个值(α和β)来减少搜索的节点数的方法。
以下是一个简单的Alpha-Beta剪枝算法的例子:假设我们正在玩一个简单的井字棋游戏,现在轮到玩家X下棋。
使用Alpha-Beta剪枝算法可以帮助玩家X决定在哪个位置下棋。
Alpha-Beta剪枝算法的步骤如下:1. 初始化:设置当前玩家为玩家X,设置α和β的值,通常α设为负无穷,β设为正无穷。
2. 开始递归搜索:从当前节点开始,递归地搜索子节点。
对于每个子节点,根据当前玩家是最大化还是最小化来更新α和β的值。
3. 判断是否需要剪枝:如果β小于等于α,表示对手已经找到了一个更好的选择,我们可以剪掉当前节点的搜索分支,不再继续搜索。
4. 返回最佳走法:如果当前节点是叶子节点,则返回该节点的值;否则,返回最佳子节点的值。
以下是这个算法的伪代码表示:```pythonfunction alphabeta(node, depth, α, β, maximizingPlayer):if depth = 0 or node is a terminal node:return the heuristic value of nodeif maximizingPlayer:value = -∞for each child of node:value = max(value, alphabeta(child, depth - 1, α, β, FALSE))α = max(α, value)if β ≤ α:breakreturn valueelse:value = +∞for each child of node:value = min(value, alphabeta(child, depth - 1, α, β, TRUE))β = min(β, value)if β ≤ α:breakreturn value```在上述代码中,`node`表示当前节点,`depth`表示当前节点的深度,`α`和`β`分别表示当前玩家的最好选择和对手的最好选择,`maximizingPlayer`表示当前玩家是最大化还是最小化。
人工智能 αβ剪枝

人工智能期中作业一字棋编程姓名:班级:学号:一、程序设计思想:1.通过判断一字棋的棋局是否与之前搜索过的棋局重复来减小搜索的复杂度。
(通过对称属性来判断是否重复)2.主程序采用递归的思想来解决此类复杂问题。
主程序的功能为按照αβ剪枝策略算出当前棋局的分数,依次递归。
int jianzhi(enzo a,int tier)为整个程序的关键函数。
其中enzo 是结构体类型(自定义),int tier 为层数。
递归如下:v[tier]=max(jianzhi(a,tier+1),v[tier]);(其中a每次传递之前都会被更新)。
3.如何判断是否是αβ剪枝是关键。
先用int v[4]数组来存储第0 、1、2、3层的分数。
初始值分别为-100,100,-100,100。
共有3种α剪枝情况和1中β剪枝情况。
详情见Int aorb();子函数。
二、程序源代码:#include <iostream>#include<vector>using namespace std;int jzs=0;int ajz=0,bjz=0;int v[4]= {-100,100,-100,100};class enzo{public:int a[3][3];//棋局enzo()//初始构造函数{for(int i=0; i<3; i++)for(int j=0; j<3; j++)a[i][j]=2;}void pr()//输出棋局{for(int i=0; i<3; i++){for(int j=0; j<3; j++){if(a[i][j]==1) cout<<'X'<<" ";if(a[i][j]==0) cout<<'O'<<" ";if(a[i][j]==2) cout<<". ";}cout<<endl;}}};//计算数组的静态估值int value_1(enzo a,int b){int v=0;for(int i=0; i<3; i++){for(int j=0; j<3; j++)if(a.a[i][j]==2) a.a[i][j]=b;}// a.pr();for(int i=0; i<3; i++)if(a.a[i][0]==b&&a.a[i][1]==b&&a.a[i][2]==b) v++;for(int i=0; i<3; i++)if(a.a[0][i]==b&&a.a[1][i]==b&&a.a[2][i]==b) v++;if(a.a[0][0]==b&&a.a[1][1]==b&&a.a[2][2]==b) v++;if(a.a[0][2]==b&&a.a[1][1]==b&&a.a[2][0]==b) v++;return v;}int value(enzo a){return(value_1(a,1)-value_1(a,0));}bool sym(enzo a,enzo b)//判断是否上下左右斜对称(没有考虑旋转的情况){if(a.a[0][1]==b.a[0][1]&&a.a[1][1]==b.a[1][1]&&a.a[2][1]==b.a[2][1]) //左右对称if(a.a[0][0]==b.a[0][2]&&a.a[1][0]==b.a[1][2]&&a.a[2][0]==b.a[2][2])if(a.a[0][2]==b.a[0][0]&&a.a[1][2]==b.a[1][0]&&a.a[2][2]==b.a[2][0]) return true;if(a.a[1][0]==b.a[1][0]&&a.a[1][1]==b.a[1][1]&&a.a[1][2]==b.a[1][2]) //上下对称if(a.a[0][0]==b.a[2][0]&&a.a[0][1]==b.a[2][1]&&a.a[0][2]==b.a[2][2])if(a.a[2][0]==b.a[0][0]&&a.a[2][1]==b.a[0][1]&&a.a[2][2]==b.a[0][2]) return true;if(a.a[0][0]==b.a[0][0]&&a.a[1][1]==b.a[1][1]&&a.a[2][2]==b.a[2][2]) //两个斜对称if(a.a[0][1]==b.a[1][0]&&a.a[0][2]==b.a[2][0]&&a.a[1][2]==b.a[2][1])if(a.a[1][0]==b.a[0][1]&&a.a[2][0]==b.a[0][2]&&a.a[2][1]==b.a[1][2]) return true;if(a.a[0][2]==b.a[0][2]&&a.a[1][1]==b.a[1][1]&&a.a[2][0]==b.a[2][0])if(a.a[0][0]==b.a[2][2]&&a.a[0][1]==b.a[1][2]&&a.a[1][0]==b.a[2][1])if(a.a[2][2]==b.a[0][0]&&a.a[1][2]==b.a[0][1]&&a.a[2][1]==b.a[1][0]) return true;return false;}bool nsym(enzo a,enzo b){if(sym(a,b)) return false;else return true;}int aorb()//a - 0 b -1{if(v[0]>=v[1]&&v[0]!=-100&&v[1]!=100){jzs++;cout<<jzs<<": "<<"发生a剪枝"<<endl;ajz++;return 1;}else if(v[0]>=v[3]&&v[0]!=-100&&v[3]!=100){jzs++;cout<<jzs<<": "<<"发生a剪枝"<<endl;ajz++;return 1;}else if(v[2]>=v[3]&&v[2]!=-100&&v[3]!=100){jzs++;cout<<jzs<<": "<<"发生a剪枝"<<endl;ajz++;return 1;}else if(v[1]<=v[2]&&v[1]!=100&&v[2]!=-100){jzs++;cout<<jzs<<": "<<"发生b剪枝"<<endl;bjz++;return 1;}else return 0;}int jianzhi(enzo a,int tier){//a.pr();if(tier==4) return value(a);if(tier%2)//极小层{vector<enzo> hi;for(int i=0; i<3; i++){for(int j=0; j<3; j++){if(a.a[i][j]==2){int u=0;int qq=0;a.a[i][j]=0;for(u=0; u<(int)hi.size(); u++){if(sym(hi[u],a)) break;}if((int)hi.size()==u){hi.push_back(a);v[tier]=min(jianzhi(a,tier+1),v[tier]); if(aorb()) qq=1;}a.a[i][j]=2;if(qq==1){a.pr();cout<<endl;v[tier]=100;return -100;}}}}int hj=v[tier];v[tier]=100;return hj;}Else//极大层{vector<enzo> hi;for(int i=0; i<3; i++){for(int j=0; j<3; j++){if(a.a[i][j]==2){int u=0;int qq=0;a.a[i][j]=1;for(u=0; u<(int)hi.size(); u++){if(sym(hi[u],a)) break;}if((int)hi.size()==u){hi.push_back(a);v[tier]=max(jianzhi(a,tier+1),v[tier]); if(aorb()) qq=1;}a.a[i][j]=2;if(qq==1){a.pr();v[tier]=-100;return 100;}}}}int hj=v[tier];v[tier]=-100;return hj;}}int main(){enzo a0;jianzhi(a0,0);cout<<"一共"<<ajz<<"次a剪枝"<<endl;cout<<"一共"<<bjz<<"次b剪枝"<<endl;}三、αβ剪枝搜索过程(其中’.’表示空)共发生了23次α剪枝,5次β剪枝。
alphabeta剪枝

alphabeta剪枝
Alpha-beta剪枝是一种搜索算法,用以减少极小化极大算法(Minimax算法)搜索树的节点数。
这是一种对抗性搜索算法,主要应用于机器游玩的二人游戏(如井字棋、象棋、围棋)。
当算法评估出某策略的后续走法比之前策略的还差时,就会停止计算该策略的后续发展。
该算法和极小化极大算法所得结论相同,但剪去了不影响最终决定的分枝。
发展分析
瓶颈
Alpha-beta剪枝本质是alpha剪枝和beta剪枝的结合,这两种剪枝的发生条件不同,因此在博弈中总是首先需要区分取极小值和取极大值方,这在一定程度上让算法的效率打了折扣。
未来发展方向
Alpha-beta剪枝是对极小化极大算法的一种改进,但是在实际应用过程中,alpha-beta剪枝首先要区分出博弈双方谁是取极大值者,谁是取极小值者,达到剪枝条件时才会进行剪枝。
这一优化方法虽然简洁明了,但在一定程度上让算法的效率打了折扣。
因此在具体的博弈中,结合博弈的特定规则进行优化,比如说,将一些先验知识(prior knowledge)纳入剪枝条件中,这种基于具体应用的优化将是alpha-beta剪枝的重要发展方向。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
人工智能大作业——极大极小算法和α -β剪枝实现一字棋学院:班级:姓名:学号:辅导老师:日期:目录一、实验目的 (3)二、实验环境 (3)三、实验原理 (3)3.1 游戏规则 (3)3.2 极小极大分析法 (3)3.3 α -β剪枝算法 (4)3.4 输赢判断算法设计 (5)四、数据结构 (5)4.1 程序流程 (5)4.2 主要成员函数 (5)4.2.1 估值函数 (5)4.2.2 Alpha-Beta 剪枝算法 (6)4.2.3 判断胜负 (6)4.2.4 鼠标左键响应 (6)4.2.5 Draw 系列函数 (6)4.2.6 COMPUTER or PLAYER 先走 (7)五、实验内容 (7)5.1 基本功能简介 (7)5.2 流程图 (8)5.2.1 估价函数 (8)5.2.2 Alpha-Beta 剪枝 (9)六、实验小结 (10)七、实验源代码 (10)一、实验目的(1) 学习极大极小搜索及α-β剪枝。
(2) 利用学到的算法实现一字棋。
二、实验环境(1) 硬件环境:网络环境中的微型计算机。
(2) 软件环境:Windows 操作系统,Microsoft Visual C++语言。
三、实验原理3.1 游戏规则"一字棋"游戏(又叫"三子棋"或"井字棋"),是一款十分经典的益智小游戏。
"井字棋" 的棋盘很简单,是一个3×3 的格子,很像中国文字中的"井"字,所以得名"井字棋"。
"井字棋"游戏的规则与"五子棋"十分类似,"五子棋"的规则是一方首先五子连成一线就胜利;"井字棋"是一方首先三子连成一线就胜利。
井字棋(英文名Tic-Tac-Toe)井字棋的出现年代估计已不可考,西方人认为这是由古罗马人发明的;但我们中国人认为,既然咱们都发明了围棋、五子棋,那发明个把井字棋自然是不在话下。
这些纯粹是口舌之争了,暂且不提。
3.2 极小极大分析法设有九个空格,由MAX,MIN 二人对弈,轮到谁走棋谁就往空格上放一只自己的棋子,谁先使自己的棋子构成"三子成一线"(同一行或列或对角线全是某人的棋子),谁就取得了胜利。
用圆圈表示MAX,用叉号代表MIN。
比如左图中就是MAX 取胜的棋局。
估价函数定义如下:设棋局为P,估价函数为e(P)。
(1) 若P 对任何一方来说都不是获胜的位置,则e(P)=e(那些仍为MAX 空着的完全的行、列或对角线的总数)-e(那些仍为MIN 空着的完全的行、列或对角线的总数)(2) 若P 是MAX 必胜的棋局,则e(P)=+∞(实际上赋了60)。
(3) 若P 是B 必胜的棋局,则e(P)=-∞(实际上赋了-20)。
比如P 如下图示,则e(P)=5-4=1需要说明的是,+∞赋60,-∞赋-20的原因是机器若赢了,则不论玩家下一步是否会赢,都会走这步必赢棋。
3.3 α -β剪枝算法上述的极小极大分析法,实际是先生成一棵博弈树,然后再计算其倒推值,至使极小极大分析法效率较低。
于是在极小极大分析法的基础上提出了α-β剪枝技术。
α-β剪枝技术的基本思想或算法是,边生成博弈树边计算评估各节点的倒推值,并且根据评估出的倒推值范围,及时停止扩展那些已无必要再扩展的子节点,即相当于剪去了博弈树上的一些分枝,从而节约了机器开销,提高了搜索效率。
具体的剪枝方法如下:(1) 对于一个与节点MIN,若能估计出其倒推值的上确界β,并且这个β值不大于MIN 的父节点(一定是或节点)的估计倒推值的下确界α,即α≥β,则就不必再扩展该MIN 节点的其余子节点了(因为这些节点的估值对MIN 父节点的倒推值已无任何影响了)。
这一过程称为α剪枝。
(2) 对于一个或节点MAX,若能估计出其倒推值的下确界α,并且这个α值不小于MAX 的父节点(一定是与节点)的估计倒推值的上确界β,即α≥β,则就不必再扩展该MAX 节点的其余子节点了(因为这些节点的估值对MAX 父节点的倒推值已无任何影响了)。
这一过程称为β剪枝。
从算法中看到:(1) MAX 节点(包括起始节点)的α值永不减少;(2) MIN 节点(包括起始节点)的β值永不增加。
在搜索期间,α和β值的计算如下:(1) 一个MAX 节点的α值等于其后继节点当前最大的最终倒推值。
(2) 一个MIN 节点的β值等于其后继节点当前最小的最终倒推值。
3.4 输赢判断算法设计因为每次导致输赢的只会是当前放置的棋子,输赢算法中只需从当前点开始扫描判断是否已经形成三子。
对于这个子的八个方向判断是否已经形成三子。
如果有,则说明有一方胜利,如果没有则继续搜索,直到有一方胜利或者搜索完整个棋盘。
四、数据结构4.1 程序流程4.2 主要成员函数4.2.1 估值函数估价函数:int CTic_MFCDlg::evaluate(int board[])完成功能:根据输入棋盘,判断当前棋盘的估值,估价函数为前面所讲:若是MAX 的必胜局,则e = +INFINITY,这里为+60若是MIN 的必胜局,则e = -INFINITY,这里为-20,这样赋值的原因是机器若赢了,则不考虑其它因素。
其它情况,棋盘上能使CUMPUTER 成三子一线的数目为e1棋盘上能使PLAYER成三子一线的数目为e2,e1-e2 作为最终权值参数:board:待评估棋盘返回:评估结果4.2.2 Alpha-Beta 剪枝算法AlphaBeta 剪枝主函数:int CTic_MFCDlg::AlphaBeta(int Board[], int Depth, int turn, int Alpha, int Beta, int *result) 完成功能:根据输入棋盘,搜索深度,及其他参数,给出一个相应的最优解,存入result 中。
参数:board :待评估棋盘Depth :搜索深度turn :当前是机器走(MAX 结点)还是玩家走(MIN 结点)Alpha :alpha 值,第一次调用默认-100Beta :beta 值,第一次调用默认+100result :输出结果返回:若当前点为MAX 节点,则返回alpha 值;若当前点为MIN 节点,则返回beta 值4.2.3 判断胜负int CTic_MFCDlg::isWin(int curPos)完成功能:根据输入棋盘,判断当前棋盘的结果,COMPUTER 胜?PLAYER 胜?平局?参数:board:待评估棋盘返回:-1 表示:尚未结束0 表示:平局1 表示:PLAYER 胜2 表示:COMPUTER 胜4.2.4 鼠标左键响应void CTic_MFCDlg::OnLButtonDown(UINT nFlags, CPoint point)完成功能:鼠标左键相应,在点击的那格放置玩家棋子,之后再相应计算机走下一步4.2.5 Draw 系列函数void CTic_MFCDlg::DrawBoard(CDC *pDC)完成功能:根据Chess 棋盘数组画出棋盘void CTic_MFCDlg::DrawO(CDC *pDC, int Pos)完成功能:在棋盘上画一个O,电脑void CTic_MFCDlg::DrawX(CDC *pDC, int Pos)完成功能:在棋盘上画一个X,玩家4.2.6 COMPUTER or PLAYER 先走void CTic_MFCDlg::OnStartCom()完成功能:计算机先走void CTic_MFCDlg::OnStartPly()完成功能:玩家先走五、实验内容5.1 基本功能简介本实验的界面采用C++的MFC 完成,总的界面如下,有以下功能:1. 搜索树深度的设置;2. 机器先走或者玩家先走;3. 游戏胜负或者平局判断。
4.鼠标在游戏开始之前或者结束之后点击棋盘不会有相应,并会提示用户先开始游戏;5.鼠标点击棋盘区域之外,不会有相应6.搜索深度已经设置区域7.同一棋盘格子点击只响应一次这里需要说明的是,搜索深度并非越深越好,局限于估值函数是根据能够成三子一线的数目决定的,所以搜索到最后一层,如果有人胜,则出现 ,如果没人胜,则三子一线数目为0,所以毫无意义。
如果搜索深度取到 4 或者以上,会发现电脑会走出一些很"笨" 的棋,就是这个原因。
经测试发现,搜索深度为2时效果最好,这也是我为什么默认值取 2 的原因。
5.2 流程图.5.2.1 估价函数5.2.2 Alpha-Beta 剪枝六、实验小结通过本次实验进一步对老师课堂上所讲的AlphaBeta 剪枝有了更加深刻的了解,对它的一般实现有了初步的认识。
复习了大二时所学习的C++语言,并且对MFC 程序设计有了更深的了解。
七、实验源代码源代码见附件‘一字棋程序’。