关于井字棋/三子棋的伪人工智能算法的实现

井字棋/三子棋的伪人工智能算法的实现

一、Abstract

本算法用于实现井字棋游戏电脑先手情况下的智能落子

二、Introduction

关于井字棋的模块的搭建,分为棋盘的初始化棋盘的展示电脑落子玩家落子判断输/赢/平局/继续游戏这5个模块。

其中,我们着重介绍一下电脑落子的具体算法。本算法可以使得玩家永远赢不了棋局。(输/平局)

本算法的核心思想为 暴力枚举迫使玩家进行指定位置的落子
注:

  1. 本棋盘为3*3的大小
  2. 电脑先手
  3. 以下用形如(2,1)的形式表示落子的坐标
  4. 用“#”表示电脑的棋子,用“*”表示玩家的棋子
  5. 代码部分使用C语言进行实现

三、Algorithm

Step1

电脑的第一步永远落于(1,1)
关于井字棋/三子棋的伪人工智能算法的实现_第1张图片

Step2

接下来,玩家落子一共有8个点可供选择,根据对称性,我们可以将其分分成5组。它们分别是:

  1. (1,2)或(2.1)
  2. (1,3)或(3,1)
  3. (2,3)或(3,2)
  4. (2,2)
  5. (3,3)

以下对于每一类情况进行分组讨论,每组以其中一种情况进行举例
蓝色的数字表示落子的顺序

A.(1,2)

关于井字棋/三子棋的伪人工智能算法的实现_第2张图片
关于井字棋/三子棋的伪人工智能算法的实现_第3张图片

上图表示玩家第一手落于(1,2)的情况。此时,显然玩家必输。
同理,玩家落子于(2,1),显然必输。

B. (1,3)

关于井字棋/三子棋的伪人工智能算法的实现_第4张图片
关于井字棋/三子棋的伪人工智能算法的实现_第5张图片

上图表示玩家第一手落于(1,3)的情况。此时,显然玩家必输。
同理,玩家落子于(3,1),显然必输。

C.(2,3)

关于井字棋/三子棋的伪人工智能算法的实现_第6张图片关于井字棋/三子棋的伪人工智能算法的实现_第7张图片

上图表示玩家第一手落于(2,3)的情况。此时,显然玩家必输。
同理,玩家落子于(3,2),显然必输。

D.(3,3)

关于井字棋/三子棋的伪人工智能算法的实现_第8张图片
关于井字棋/三子棋的伪人工智能算法的实现_第9张图片

上图表示玩家第一手落于(3,3)的情况。此时,显然玩家必输。

E.(2,2)

关于井字棋/三子棋的伪人工智能算法的实现_第10张图片
上图表示玩家第一手落于(2,2)的情况。此时,显然最终双方会握手言和。

Step3

以下展示电脑落子的代码

首先需定义棋盘大小

#define ROW 3
#define COL 3

首先创建一个3*3的二维数组

char board[3][3]={
     0};

并将二维数组中每一个元素使用初始化模块初始化为’ ’ ,也就是空格,此处省略

我们另需封装一个CountNum函数用来统计棋盘中的9个格子已经有几个格子上落了子

int CountNum(char board[ROW][COL], int row, int col)
{
     
	int count = 0;
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
     
		for (j = 0; j < col; j++)
		{
     
			if (board[i][j] != ' ')
				count++;
		}
	}
	return count;
}

以下代码为具体的电脑落子智能算法,其中参数board表示用来表示棋盘的二维数组的地址,row为ROW(3),col为COL(3)

void ComputerMove(char board[ROW][COL], int row, int col)
{
     
	int x = 0;
	int y = 0;
	if (CountNum(board, ROW, COL) == 0)
	{
     
		board[0][0] = '#';
	}
	if (CountNum(board, ROW, COL) == 2)
	{
     

		//5 types , 8 situations

		// 1
		if (board[0][1] == '*')
		{
     
			board[2][0] = '#';
		}
		// 2
		if (board[1][0] == '*')
		{
     
			board[0][2] = '#';
		}
		// 3 
		if (board[0][2] == '*')
		{
     
			board[2][2] = '#';
		}
		// 4
		if (board[2][0] == '*')
		{
     
			board[2][2] = '#';
		}
		// 5
		if (board[2][1] == '*')
		{
     
			board[2][0] = '#';
		}
		// 6
		if (board[1][2] == '*')
		{
     
			board[0][2] = '#';
		}
		// 7
		if (board[1][1] == '*')
		{
     
			board[0][1] = '#';
		}
		// 8
		if (board[2][2] == '*')
		{
     
			board[0][2] = '#';
		}
	}
	if (CountNum(board, ROW, COL) == 4)
	{
     
		// 1@1
		if (board[0][1] == '*' && board[2][0] == '#')
		{
     
			if (board[1][0] == '*')
			{
     
				board[2][2] = '#';
			}
			else
			{
     
				board[1][0] = '#';
			}
		}
		// 2@1
		if (board[1][0] == '*' && board[0][2] == '#')
		{
     
			if (board[0][1] == '*')
			{
     
				board[2][2] = '#';
			}
			else
			{
     
				board[0][1] = '#';
			}
		}
		// 3@1
		if (board[0][2] == '*' && board[2][2] == '#')
		{
     
			if (board[1][1] == '*')
			{
     
				board[2][0] = '#';
			}
			else
			{
     
				board[1][1] = '#';
			}
		}
		// 4@1
		if (board[2][0] == '*' && board[2][2] == '#')
		{
     
			if (board[1][1] == '*')
			{
     
				board[0][2] = '#';
			}
			else
			{
     
				board[1][1] = '#';
			}
		}
		// 5@1
		if (board[2][1] == '*' && board[2][0] == '#')
		{
     
			if (board[1][0] == '*')
			{
     
				board[0][2] = '#';
			}
			else
			{
     
				board[1][0] = '#';
			}
		}
		// 6@1
		if (board[1][2] == '*' && board[0][2] == '#')
		{
     
			if (board[0][1] == '*')
			{
     
				board[2][0] = '#';
			}
			else
			{
     
				board[0][1] = '#';
			}
		}
		// 7@1
		if (board[1][1] == '*' && board[0][1] == '#')
		{
     
			if (board[0][2] == '*')
			{
     
				board[2][0] = '#';
			}
			else
			{
     
				board[0][2] = '#';
			}
		}
		// 8@1
		if (board[2][2] == '*' && board[0][2] == '#')
		{
     
			if (board[0][1] == '*')
			{
     
				board[2][0] = '#';
			}
			else
			{
     
				board[0][1] = '#';
			}
		}
	}
	if (CountNum(board, ROW, COL) == 6)
	{
     
		// 1@1@1
		if (board[0][0] == '#' && board[2][0] == '#' && board[2][2] == '#' && board[0][1] == '*' && board[1][0] == '*')
		{
     
			if (board[1][1] == ' ')
			{
     
				board[1][1] = '#';
			}
			else
			{
     
				board[1][1] = '#';
			}
		}
		// 2@1@1
		if (board[0][0] == '#' && board[0][2] == '#' && board[2][2] == '#' && board[0][1] == '*' && board[1][0] == '*')
		{
     
			if (board[1][1] == ' ')
			{
     
				board[1][1] = '#';
			}
			else
			{
     
				board[1][1] = '#';
			}
		}
		// 3@1@1
		if (board[0][0] == '#' && board[2][0] == '#' && board[2][2] == '#' && board[0][2] == '*' && board[1][1] == '*')
		{
     
			if (board[1][0] == ' ')
			{
     
				board[1][0] = '#';
			}
			else
			{
     
				board[2][1] = '#';
			}
		}
		// 4@1@1
		if (board[0][0] == '#' && board[0][2] == '#' && board[2][2] == '#' && board[2][0] == '*' && board[1][1] == '*')
		{
     
			if (board[0][1] == ' ')
			{
     
				board[0][1] = '#';
			}
			else
			{
     
				board[1][2] = '#';
			}
		}
		// 5@1@1
		if (board[0][0] == '#' && board[2][0] == '#' && board[0][2] == '#' && board[1][0] == '*' && board[2][1] == '*')
		{
     
			if (board[0][1] == ' ')
			{
     
				board[0][1] = '#';
			}
			else
			{
     
				board[1][1] = '#';
			}
		}
		// 6@1@1
		if (board[0][0] == '#' && board[0][2] == '#' && board[2][0] == '#' && board[0][1] == '*' && board[1][2] == '*')
		{
     
			if (board[1][0] == ' ')
			{
     
				board[1][0] = '#';
			}
			else
			{
     
				board[1][1] = '#';
			}
		}
		// 7@1@1
		if (board[0][0] == '#' && board[0][1] == '#' && board[2][0] == '#' && board[1][1] == '*' && board[0][2] == '*')
		{
     
			if (board[1][0] == '*')
			{
     
				board[1][2] = '#';
			}
			else
			{
     
				board[1][0] = '#';
			}
		}
		// 8@1@1
		if (board[0][0] == '#' && board[0][2] == '#' && board[2][0] == '#' && board[0][1] == '*' && board[2][2] == '*')
		{
     
			if (board[1][0] == ' ')
			{
     
				board[1][0] = '#';
			}
			else
			{
     
				board[1][1] = '#';
			}
		}
	}
	if (CountNum(board, ROW, COL) == 8)
	{
     
		//7@1@1@1
		if (board[0][0] == '#' && board[0][1] == '#' && board[1][2] == '#' && board[2][0] == '#' && board[0][2] == '*' && board[1][0] == '*' && board[1][1] == '*')
		{
     
			if (board[2][1] == '*')
			{
     
				board[2][2] = '#';
			}
			else
			{
     
				board[2][1] = '#';
			}
		}
	}
}

四、Acknowledgment

谢谢我自己能在大一下期中考前抽出半天来研究这样一个看似挺无聊的问题

谢谢小伙伴们能够看完这篇文章

附上GitHub完整代码

如果想要深入了解AI对弈,可以去看看极大极小算法(Minimax)

本人目前水平有限,如有错误,望指正

2021.4.24 姑苏阴雨绵绵

你可能感兴趣的:(c语言,c语言,算法,游戏,人工智能)