博弈之最大最小搜索搜索

本文介绍了如何使用Minimax算法和α-β剪枝来创建黑白棋的AI。通过理解max和min局面,建立局面估价函数,并根据边角重要性设计估值表。AI的难度设计分为简单、中等和困难,主要区别在于搜索深度。简单AI采用贪心策略,中等和困难AI则结合深度搜索。通过α-β剪枝优化搜索效率,降低计算复杂度。
摘要由CSDN通过智能技术生成

写这篇博客的目的呢,是因为做(嫖)了一个黑白棋的课设,就对这玩意产生了点兴趣,还请个位指教!

Minimax算法

Minimax算法大多被用于棋类游戏中,是一种找出失败的最大可能性中的最小值的算法,即最小化对手的最大得益的算法,就是说想将自己的分数尽量高,而对手尽量选取小的值的算法。

首先先来了解一下这几个概念

局面估价函数:我们给每个局面(state)规定一个估价函数值 f,评价它对于己方的有利程度。胜利的局面的估价函数值为 +oo,而失败的局面的估价函数值为–oo。

Max 局面:假设这个局面轮到己方走,有多种决策可以选择,其中每种决策都导致一种子局面(sub-state)。由于决策权在我们手中,当然是选择估价函数值 f 最大的子局面,因此该局面的估价函数值等于子局面 f 值的最大值,把这样的局面称为 max 局面。

Min 局面:假设这个局面轮到对方走,它也有多种决策可以选择,其中每种决策都导致一种子局面(sub-state)。但由于决策权在对方手中,在最坏的情况下,对方当然是选择估价函数值 f 最小的子局面,因此该局面的估价函数值等于子局面 f 值的最小值,把这样的局面称为 max 局面。

现在看这么一个博弈树

在这里插入图片描述
画的好像有点烂,不过没关系的。
现在我和你进行博弈下棋,我先手,我在下棋的时候,当然会想着取到最好的结果,这个结果我们用之前提到的估值来表示,在那个博弈树里面,最后一层代表着估值,我先手,我当然希望我得到最大的估值,那我的那一步也就是那个节点的估值要从下面的节点开始,我们是max局面,就是取得最好值,你对我来说应该取到min局面,为什么我说那你取得是min局面呢??因为你看那个博弈搜索树,我下一步,你下一步,你的min值决定了我的max值,就说第三层和第四层,1 和 -4,你在第五层取-4的时候,也可以取3,但你要是取了3,对我的max局面来说就会取到3,而不是1了。

那我们在设计棋类算法的时候,就要考虑到每个点的估值。

黑白棋中的估值表

多玩几次黑白棋,那就会发现,边角上的棋子很重要,黑白棋的游戏规则就不说了,总之就是边角上的 棋子很重要,在边角旁边的棋子又很危险,因为放置在这里,最后可能会被一波转化掉,根据经验,我们可以得到一个估值表。
在这里插入图片描述
这样在AI决策的时候就会方便许多。

对于AI的设定,我们能走边角就尽量走边角,不到万不得已的情况下,不走邻角点,对于其他情况,我们采用极大极小算法。

α-β剪枝

经过查阅可以得知,六层的搜索就接近是二十亿,而十层的搜索就超过两千万亿,so??
就有了所谓的α-β剪枝。
怎么理解这个α-β剪枝呢?
就还拿我上面画的图举例子。我们看第二层吧,1和9,第二层的那个9的选取,第三层的第二个节点是10,第三个节点是9,假如说我们已经已知了9,对第三层10选取的时候,我只知道第四层的第四个是10,第四层的第三个节点假设不清楚,那么第三层的那个节点值它肯定是>=10的吧,因为这里为max决策,然后上一层为min决策,那再10下面的哪一片就可以剪枝掉,这种剪枝方式局叫做α-β剪枝。

简单难度AI设计

这个简单难度的AI就简单设计,AI的算法为贪心算法,寻找每次可以转换最多点。说实话,这个简单AI属实拉跨,我用贪心思想跟AI的贪心算法下,AI有的时候下不过我,哈哈哈哈哈!

POINT2 Easy()										//人机对战简单AI
{
	POINT2 MAX;										//定义以及初始化最优解
	MAX.INIT(0, 0);
	int maxx = 0;
	for (int i = 0; i < SIZE; ++i)
		for (int j = 0; j < SIZE; ++j)
		{
			if (expect[i][j] >= maxx)				//寻找可以转化棋子最多的点作为最优解
			{
				maxx = expect[i][j];
				MAX.INIT(i, j);
			}
		}
	if (ESCEXIT)gameStart();
	Sleep(800);										//间歇
	return MAX;										//返回最优解
}

纯贪心思想,使用之前给到的每个点的估值进行判断的。

中等难度AI的设计

POINT2 MIDDLE()									//人机对战中等AI
{
	POINT2 MAX;
	int maxx = -10005;
	MAX.INIT(0, 0);
	for (int i = 0; i < SIZE; i++)
		for (int j = 0; j < SIZE; j++)
		{
			if (expect[i][j])
			{
				if ((i == 0 && j == 0) || (i == 0 && j == SIZE - 1) || (i == SIZE - 1 && j == SIZE - 1) || (i == SIZE - 1 && j == 0))
				{
					MAX.INIT(i, j);
					return MAX;										//如果在角,返回角坐标
				}
				int k = difai(i, j, mapp, expect, 0, 1);					//递归搜索 搜索一层
				if (k >= maxx)
				{
					maxx = k;
					MAX.INIT(i, j);
				}
			}
		}
	return MAX;
}

困难难度AI

困难难度和中等难度的区别就是搜索的深度不同,通俗点讲的话就是我们下棋可以一眼看几步

POINT2 Difficult()									//人机对战困难AI
{
	POINT2 MAX;
	int maxx = -10005;
	MAX.INIT(0, 0);
	for (int i = 0; i < SIZE; i++)
		for (int j = 0; j < SIZE; j++)
		{
			if (expect[i][j])
			{
				if ((i == 0 && j == 0) || (i == 0 && j == SIZE - 1) || (i == SIZE - 1 && j == SIZE - 1) || (i == SIZE - 1 && j == 0))
				{
					MAX.INIT(i, j);
					return MAX;										//如果在角,返回角坐标
				}
				int k = difai(i,j,mapp,expect,0,3);					//递归搜索 搜索三层
				if (k >= maxx)
				{
					maxx = k;
					MAX.INIT(i, j);
				}
			}
		}
	return MAX;
}

最大最小搜索搜索算法

还是递归的运用,至于剪枝,是有一点点啦

int difai(int x,int y,int mapnow[SIZE][SIZE],int expectnow[SIZE][SIZE],int depin,int depinmax)						//极大极小搜索
{
	if (depin >= depinmax)return 0;											//递归出口

	int maxx = -10005;														//最大权值
	POINT2 NOW;
	int expectnow2[SIZE][SIZE] , mapnow2[SIZE][SIZE],mapnext[SIZE][SIZE],expectlast[SIZE][SIZE];					//定义临时数组

	copymap(mapnow2, mapnow);												//复制当前棋盘

	mapnow2[x][y] = NOWCOLOR ? 1 : -1;										//模拟在当前棋盘上下棋
	int ME = MAPPOINTCOUNT[x][y] + expectnow[x][y];							//当前棋子权
	NOW.INIT(x,y);

	Change(NOW, mapnow2, false);											//改变棋盘AI结束

	int MAXEXPECT = 0, LINEEXPECT = 0, COUNT = 0;
	for (int i = 0; i < SIZE; ++i)
		for (int j = 0; j < SIZE; ++j)
		{
			expectnow2[i][j] = Judge(i, j, !NOWCOLOR, mapnow2);				//预判对方是否可以走棋
			if (expectnow2[i][j])
			{
				++MAXEXPECT;
				if ((i == 0 && j == 0) || (i == 0 && j == SIZE - 1) || (i == SIZE - 1 && j == SIZE - 1) || (i == SIZE - 1 && j == 0))return -1800;	//如果对方有占角的可能
				if ((i < 2 && j < 2) || (i < 2 && SIZE - j - 1 < 2) || (SIZE - 1 - i < 2 && j < 2) || (SIZE - 1 - i < 2 && SIZE - 1 - j < 2))++LINEEXPECT;
			}
		}
	if (LINEEXPECT * 10 > MAXEXPECT * 7)return 1400;						//如果对方走到坏点状态较多 剪枝

	for (int i = 0; i < SIZE; i++)
		for (int j = 0; j < SIZE; j++)
			if (expectnow2[i][j])											//如果对方可以走棋
			{
				int YOU = MAPPOINTCOUNT[i][j] + expectnow2[i][j];			//当前权值
				copymap(mapnext, mapnow2);									//拷贝地图
				mapnext[i][j] = (!NOWCOLOR) ? 1 : -1;						//模拟对方走棋
				NOW.INIT(i, j);
				Change(NOW, mapnext, false);								//改变棋盘

				for (int k = 0; k < SIZE; k++)
					for (int l = 0; l < SIZE; l++)
						expectlast[k][l] = Judge(k, l, NOWCOLOR, mapnext);	//寻找AI可行点

				for (int k = 0; k < SIZE; k++)
					for (int l = 0; l < SIZE;l++)
						if (expectlast[k][l])
						{
							int nowm = ME - YOU + difai(k, l, mapnext, expectlast, depin + 1, depinmax);
							maxx = maxx < nowm ? nowm : maxx;
						}
			}
	return maxx;
}

本课设以征求开源作者同意使用,本来博主是拒绝白嫖的,ue4不香吗,垃圾玩意崩溃打不开项目了,也就有了这篇博文.

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值