AI五子棋第二篇-运用极大极小值算法书写AI三子棋,可拓展到五子棋(建议收藏)

Posted Ja_king_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AI五子棋第二篇-运用极大极小值算法书写AI三子棋,可拓展到五子棋(建议收藏)相关的知识,希望对你有一定的参考价值。

前言:本文采用极大极小值算法实现AI三子棋,可拓展到五子棋,不过五子棋效率过低,建议五子棋采用Alpha-Beta剪枝算法。

一.棋盘的初始化及打印

首先建立一个3*3的二维数组,此处采用宏定义行和列的方式,方便以后修改为五子棋。

#define ROW 3
#define COL 3

然后对棋盘进行初始化操作

    //棋盘数组
	char board[ROW][COL],ret;
	//初始化棋盘
	InitBoard(board, ROW, COL);

此处将棋盘初始化为空格,大家可初始化为其他。

void InitBoard(char board[ROW][COL], int row, int col) {
	for (int i = 0;i < row;i++) {
		for (int j = 0;j < col;j++) {
			board[i][j] = ' ';
		}
	}
}

打印棋盘

    //打印棋盘
	PrintBoard(board, ROW, COL);
void PrintBoard(char board[ROW][COL], int row, int col) {
	for (int i = 0;i < row;i++) {
		printf("  ");
		printf("%2d", i+1);
	}
	printf("\\n");
	for (int i = 0;i < row;i++) {
		//打印数据
		printf("%2d", i + 1);
		for (int j = 0;j < col;j++) {
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}
		printf("\\n");
		//打印分割行
		if (i < row - 1) {
			printf("  ");
			for (int j = 0;j < col;j++) {

				printf("---");
				if (j < col-1)
					printf("|");
			}
			printf("\\n");
		}
	}
}

二.玩家下棋以及判断输赢函数

此处的目的是为了选择先后手

printf("1.先手 0.后手");
	scanf("%d", &a);
	if(a==1)
		PlayerMove(board, ROW, COL);
	else
		ComputerMove(board, ROW, COL);

玩家下棋

void PlayerMove(char board[ROW][COL], int row, int col) {
	int x, y;
	while (1) {
		printf("玩家走:\\n");
		printf("请输入坐标:\\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col) {
			if (board[x - 1][y - 1] == ' ') {
				board[x - 1][y - 1] = 'O';
				break;
			}
			else {
				printf("坐标被占用,请重新输入\\n");
			}
		}
		else {
			printf("坐标非法,请重新输入\\n");
		}
	}
}

判断输赢函数(由于要拓展到五子棋,所以封装的函数才用遍历整个棋盘,观察是否有连三的情况出现)

char iswin(char board[ROW][COL], int row, int col) {
	//行
	int ren=0,dian=0,i,j;
	for (i = 0;i < row;i++) {
		ren = 0;
		for (j = 0;j < col;j++) {
			if (board[i][j] == 'O')
				ren++;
			else
				ren = 0;
			if (ren >= 3)
				return 'O';
		}
		
	}
	for (i = 0;i < row;i++) {
		dian = 0;
		for (j = 0;j < col;j++) {
			if (board[i][j] == 'X')
				dian++;
			else
				dian = 0;
			if (dian >= 3)
				return 'X';
		}
		
	}
	//列
	ren = dian = 0;
	for (i = 0;i < row;i++) {
		ren = 0;
		for (j = 0;j < col;j++) {
			if (board[j][i] == 'O')
				ren++;
			else
				ren = 0;
			if (ren >= 3)
				return 'O';
		}
		
	}
	for (i = 0;i < row;i++) {
		dian = 0;
		for (j = 0;j < col;j++) {
			if (board[j][i] == 'X')
				dian++;
			else
				dian = 0;
			if (dian >= 3)
				return 'X';
		}
		
	}
	//右下
	ren = dian =i=j= 0;
	for (int k = 0;k < row;k++) {
		i = k;
		j = 0;
		ren = 0;
		while (i < row && j < col) {
			if (board[i][j] == 'O') {
				ren++;
			}
			else {
				ren = 0;
			}
			i++;
			j++;
			if (ren >= 3)
				return 'O';
		}
		
	}
	i = j = 0;
	for (int k = 0;k < row;k++) {
		i = k;
		j = 0;
		dian = 0;
		while (i < row && j < col) {
			if (board[i][j] == 'X') {
				dian++;
			}
			else
				dian = 0;
			i++;
			j++;
			if (dian >= 3)
				return 'X';
		}
		
	}
	//右上
	for (int k = row;k >=0;k--) {
		j = col;
		i = k;
		ren = 0;
		while (i >=0 && j >=0) {
			if (board[i][j] == 'O') {
				ren++;
			}
			else
				ren = 0;
			i--;
			j--;
			if (ren >= 3)
				return 'O';
		}

	}
	
	for (int k = row;k >= 0;k--) {
		i = k;
		j = col;
		dian = 0;
		while (i >= 0 && j >= 0) {
			if (board[i][j] == 'X') {
				dian++;
			}
			else
				dian = 0;
			i--;
			j--;
			if (dian >= 3)
				return 'X';
		}
		
	}
	
	//左
	for (int k = row;k >= 0;k--) {
		i = k;
		j = 0;
		dian = 0;
		while (i >= 0 && j <col) {
			if (board[i][j] == 'O') {
				dian++;
			}
			else
				dian = 0;
			i--;
			j++;
			if (dian >= 3)
				return 'O';
		}

	}
	for (int k = row;k >= 0;k--) {
		i = k;
		j = 0;
		dian = 0;
		while (i >= 0 && j <col) {
			if (board[i][j] == 'X') {
				dian++;
			}
			else
				dian = 0;
			i--;
			j++;
			if (dian >= 3)
				return 'X';
		}

	}
	for (int k = 0;k < row;k++) {
		i = k;
		j = col;
		dian = 0;
		while (i < row && j >= 0) {
			if (board[i][j] == 'O') {
				dian++;
			}
			else
				dian = 0;
			i++;
			j--;
			if (dian >= 3)
				return 'O';
		}

	}
	for (int k = 0;k <row;k++) {
		i = k;
		j = col;
		dian = 0;
		while (i <row && j >= 0) {
			if (board[i][j] == 'X') {
				dian++;
			}
			else
				dian = 0;
			i++;
			j--;
			if (dian >= 3)
				return 'X';
		}

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

三.电脑下棋,AI算法的实现(重点)

1.如何实现AI:
首先,要对局势进行打分,如下图:

和局:0
双方均无优势:±1
某方有连三:±100
此处打分也采用宏定义:

#define INFINITY 100
#define INPROGRESS 1
#define DRAW 0
#define WIN  (+INFINITY)
#define LOSE (-INFINITY)

其次,搜索最佳走法:

比如,棋盘现如上图所示,有三点可以下棋,那么哪步对计算机是有利的呢?我们知道,下A或C点电脑就输了,只能下B点,所以这里采用极大极小值算法,对棋盘进行遍历搜索出最佳走法,具体实现如下图:

所以此处封装两个函数,分别为maxSearch和minSearch。

** maxSearch的功能是:**当计算机方走出一招棋后,评价计算机自己的局面。
** minSearch的功能是:**当人方走出一招棋后,评价计算机的局面。
所以,maxSearch函数一定会找到对电脑最有利的走法,而minSearch找到对玩家最有利的走法

void ComputerMove(char board[ROW][COL], int row, int col) {
	int i, j;
	bool blBoardEmpty = true;

	/*if (BoardIsFull()) return;*/

	//这个双层for循环检查棋盘是否没有任何棋子。
	for (i = 0;i < ROW;i++)
	{
		for (j = 0;j < COL;j++)
		{
			if (board[i][j] != ' ')
			{
				blBoardEmpty = false;
				break;
			}
		}
		if (blBoardEmpty == false)
			break;
	}

	//如果棋盘为空,表明是计算机先手执黑,随意选一个点落子即可。
	if (blBoardEmpty == true)
	{
		/*srand( (unsigned)time( NULL ) );
		i=rand()%m_edge;
		j=rand()%m_edge;*/
		//board[9][9] = 'X';
	}
	else//搜索最佳招法。
	{
		cpoint ret = minimax(board);
		if (ret.x == -1) return;
		i = ret.x;
		j = ret.y;
	}
	board[i][j] = 'X';
}

棋盘为空时,表明是计算机先手执黑,随意选一个点落子即可。
else,则搜索最佳走法
具体搜索算法(极大极小值算法)如下:

//maxSearch的功能是:当计算机方走出一招棋后,评价计算机自己的局面。
int maxSearch(char board[ROW][COL])
{
	int i, j;
	int positionValue = 0;
	if (iswin(board, ROW, COL) == 'X') {
		positionValue = +INFINITY;
	}
	if (iswin(board, ROW, COL) == 'O') {
		positionValue = -INFINITY;
	}
	if (iswin(board, ROW, COL) == 'C') {
		positionValue = INPROGRESS;
	}
	if (iswin(board, ROW, COL) == 'Q') {
		positionValue = DRAW;
	}
	if (positionValue == DRAW) return 0;
	if (positionValue != INPROGRESS) return positionValue;
	int bestValue = -INFINITY;
	m_nodes++;
	for (i = 0; i < ROW; i++)
		for (j = 0;j < COL;j++)
			if (board[i][j] == ' ')
			{
				board[i][j] = 'X';
				int value = minSearch(board);
				if (value > bestValue)
					bestValue = value;
				board[i][j] = ' ';
			}

	return bestValue;
}
//minSearch的功能是:当人方走出一招棋后,评价计算机的局面。
int minSearch(char board[ROW][COL]五子棋AI算法第三篇-Alpha Beta剪枝

[程序设计]-基于人工智能博弈树,极大极小(Minimax)搜索算法并使用Alpha-Beta剪枝算法优化实现的可人机博弈的AI智能五子棋游戏。

C语言一个小时实现简易三子棋,看看你能不能让愚蠢的电脑获胜,还不快上手试试吗(无AI算法)

人机ai五子棋 ——五子棋AI算法之Java实现

五子棋AI算法-迭代加深

C语言人工智能 |教你与智能AI对弈三子棋 从此不再孤单寂寞冷