博弈三连棋alpha_beta

三连棋作为计算机博弈的入门棋,运用alpha-beta来产生最优招法

除了发现当前局面已经必输,输出最靠前的招法,其它局面都输出必胜或者必平招法。

O

..X

.O.

X..

0 1

三连棋的估值比较直接简单,只有胜,负,平3中结局,我定义为了10,0,-10。而某一玩家发现当前局面已经胜负已出,也就说明当前玩家已经输了(color交换的问题,不可能出现对手下了一子后发现自己莫名奇妙的赢了~_~),alpha-beta模拟过程中,估值由负极大值搜索返回到父亲节点时,该节点的alpha也就是当前局面下,当前执子的玩家的局面估值,如果局面已输就估值赋值为-10;

因此估值问题只有两种局面,判断GameOver 是平局则当前color估值为0,否则当前color的局面估值就是-10;

估值问题解决好了,剩下就是要处理先后手的问题了,通过SearchGoodMove查询到先手玩家的最优招法后,如果你作为后手玩家,在此局面上再次调用一次SearchGoodMove就能够解决。还有就是必输的局面,如果发现通过alpha-beta返回的val是-10,也就是当前局面该玩家必输,则输出棋局上最靠前的招法。

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#define INF 999999
char map[5][5], player,enermy;
int fbx[10],fby[10],k;

int checkwin()//判断在未填满棋局时游戏是否已经结束
{
	if (map[0][0] == map[0][1] && map[0][1] == map[0][2])
	{
		if (map[0][0] == player)
			return 1;
		else if (map[0][0] == enermy)
			return 1;
	}
	if (map[1][0] == map[1][1] && map[1][1] == map[1][2])
	{
		if (map[1][0] == player)
			return 1;
		else if (map[1][0] == enermy)
			return 1;
	}
	if (map[2][0] == map[2][1] && map[2][1] == map[2][2])
	{
		if (map[2][0] == player)
			return 1;
		else if (map[2][0] == enermy)
			return 1;
	}
	if (map[0][0] == map[1][0] && map[1][0] == map[2][0])
	{
		if (map[0][0] == player)
			return 1;
		else if (map[0][0] == enermy)
			return 1;
	}
	if (map[0][1] == map[1][1] && map[1][1] == map[2][1])
	{
		if (map[0][1] == player)
			return 1;
		else if (map[0][1] == enermy)
			return 1;
	}
	if (map[0][2] == map[1][2] && map[1][2] == map[2][2])
	{
		if (map[0][2] == player)
			return 1;
		else if (map[0][2] == enermy)
			return 1;
	}
	if (map[0][0] == map[1][1] && map[1][1] == map[2][2])
	{
		if (map[0][0] == player)
			return 1;
		else if (map[0][0] == enermy)
			return 1;
	}
	if (map[0][2] == map[1][1] && map[1][1] == map[2][0])
	{
		if (map[0][2] == player)
			return 1;
		else if (map[0][2] == enermy)
			return 1;
	}
	return 0;
}

int Evaluate()//估值:只要胜负已出,当前玩家面对的都是输的局面,因此不是平局则估值为-10
{
	if (checkwin() == 1)
	{
		return -10;
	}
	else
	{
		return 0;
	}
}

void MakeNextMove(int x, int y,int turn)//执行下棋
{
	if (turn)
		map[x][y] = player;
	else
		map[x][y] = enermy;
}

void UnMakeMove(int x, int y)//恢复棋盘
{
	map[x][y] = '.';
}

int AlphaBeta(int depth, int alpha, int beta, int turn)//alpha-beta搜索
{
	int i, j, val;
	if (depth == 0)
	{
		return Evaluate();
	}
	if (checkwin() == 1)
	{
		return -10;
	}
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
			if (map[i][j] == '.')
			{
				MakeNextMove(i, j, turn);
				val = -AlphaBeta(depth - 1, -beta, -alpha, 1 - turn);
				UnMakeMove(i, j);
				if (val >= beta)
				{
					return val;
				}
				if (val > alpha)
				{
					alpha = val;
				}
			}
		}
	}
	return alpha;
}

void SearchGoodMove(int depth, int alpha, int beta, int turn)//寻找当前局面最佳招法并打印
{
	int i, j, val;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
			if (map[i][j] == '.')
			{

				MakeNextMove(i, j, turn);
				val = -AlphaBeta(depth - 1, -beta, -alpha, 1 - turn);
				UnMakeMove(i, j);
				if (val == 10 && turn==1)//先手且必胜则输出最前招法
				{
					printf("%d %d\n", i, j);
					return ;
				}
				if (turn == 0 && val==10)//后手必败则递归调用一次将后手处理为先手
				{
					MakeNextMove(i, j, turn);
					SearchGoodMove(depth - 1, -beta, -alpha, 1 - turn);
					UnMakeMove(i, j);
					return ;
				}
				if (val >= 0 && turn==1)//先手必平则先保存起必平招法
				{
					fbx[k] = i;
					fby[k++] = j;
				}
			}
		}
	}
	if (turn == 0)
	{
		for (i = 0; i < 3; i++)
		{
			for (j = 0; j < 3; j++)
			{
				if (map[i][j] == '.')
				{

					MakeNextMove(i, j, turn);
					val = -AlphaBeta(depth - 1, -INF, INF, 1 - turn);
					SearchGoodMove(depth - 1, -INF, INF, 1 - turn);//后手没有必输则递归一次转换为先手
					return;
				}
			}
		}
	}
	if (k == 0)//没有比平招法就必输,输出第一个招法
	{
		for (i = 0; i < 3; i++)
		{
			for (j = 0; j < 3; j++)
			{
				if (map[i][j] == '.')
				{
					printf("%d %d\n", i, j);
					return ;
				}
			}
		}
	}
	else//有必平招法则输出第一个
		printf("%d %d\n", fbx[0], fby[0]);
}

int main()
{
	int i, j, dep, t;
	while (~scanf("%c", &player))
	{
		while(player == '\n')
			player = getchar();
		if (player == '.')
			return 0;
		if (player == 'O')
			enermy = 'X';
		if (player == 'X')
			enermy = 'O';
		dep = 0;
		k = 0;
		for (i = 0; i < 3; i++)
		{
			scanf("%s", map[i]);
		}
		for (i = 0; i < 3; i++)
		{
			for (j = 0; j < 3; j++)
			{
				if (map[i][j] == '.')
					dep++;
			}
		}
		if (dep % 2 && player == 'X')
			t = 1;
		else if (dep % 2 == 0 && player == 'O')
			t = 1;
		else
			t = 0;
		memset(fbx, 0, sizeof(fbx));
		memset(fby, 0, sizeof(fby));
		SearchGoodMove(dep, -INF, INF, t);
	}
	return 0;
}

你可能感兴趣的:(博弈)