0
点赞
收藏
分享

微信扫一扫

JAVA中的基本数据类型

阎小妍 2023-06-29 阅读 48
算法

正文

01

思路

我没有选择专业的五子棋棋型,用我自己的逻辑(初高中玩五子棋的方法),去实现简单的人机对战。

首先因为要计算五子棋每一步的分数,那么你就要分析每一步形成的棋盘,以下图为例:

当你即将在红色方框区域内落子时,通过数据处理获取四个方向的棋子存储在数组里面,然后就是分析这个数组属于那种棋型。


以横向为例:

row相当于上图红色矩形区域的行坐标

col 相当于上图红色矩形区域的列坐标

player是这个位置即将落子的颜色,-1黑子    1 白子

int Game_score(int row, int col, int player)	//player = -1黑子	player = 1 白子
{

	char arr[4][9] = { 0 };	//存放四个方向的棋子
	int grade[4];			//存放四个方向的总分
	int begin = 0, end = 0;
	/*========左右========*/
	//从Map[row][col]处往左找四个棋子,遇到边界结束得到左边落子数量
	//从Map[row][col]处往右找四个棋子,遇到边界结束得到右边落子数量
	for (int index = 1; index <= 4; index++)
	{
		//往左找
		if (col - index >= 0)
		{
			begin = index;
		}
		//往右找
		if (col + index < 15)
		{
			end = index;
		}
	}
	for (int temp = 0, index = col - begin; index <= col + end; index++, temp++)
	{
		arr[0][temp] = Map[row][index];	//将Map[row][col]附近九个位置的棋子放入到arr里面分析
	}
	arr[0][begin] = player;			//将预测的落子位置由0置player
}

这个时候横向的棋子已经存储在arr这个数组的第一行这个时候只需要分析横向的棋型属于那种类型。

这里插句嘴,当时我处理完得到四个方向的棋型之后我觉得五子棋AI已经完成了一大半,然而在判断每个方向属于那种棋型的时候我慌了。

我觉得将所有棋型,也就是专业的连五,活四,冲四,活三,眠三,活二,眠二这些棋型枚举出来,然后和这个arr数组匹配就完事了。一枚举,十五种可能的棋型,还不是固定大小,下面是我当时枚举的情况

int g_score[15][6] = {
	/*连五*/
	{1,1,1,1,1},
	/*活四*/
	{0,1,1,1,1,0},
	/*冲四*/
	{0,1,1,1,1,-1},
	{1,0,1,1,1},
	{1,1,0,1,1},
	/*活三*/
	{0,1,1,1,0},
	{1,0,1,1},
	//{1,1,0,1},
	/*眠三*/
	{1,1,1,-1},
	{1,0,1,1,-1},
	{1,1,0,1,-1},
	{1,0,0,1,1},
	{1,0,1,0,1},
	/*活二*/
	{1,1},
	{1,0,1},
	{1,0,0,1},
};

先不管棋型的宽度有6有2,尝试匹配,一算算了近3s,时间复杂度太高了,而且还算错了,还是因为棋型宽度不一致,匹配起来很难,当时我还想要不然用C++里面的string类里面的find函数去匹配,后面忘记了还是咋,换成了最简单的方法,就是看下当前落子位置相连的棋子数量为多少。

int count = 1;	//统计连子数量
/*从Map[row][col]往左找,统计player棋子的数量*/
for (int i = 1; i <= begin; i++)
{
	if (arr[0][begin - i] == player)
	{
		count++;
	}
	elseif (arr[0][begin - i] == -player)
	{
		if (count < 5)	//当最左边有一个异类棋子时权重降低 例如 xoooo 和 ooo	权重一样	
			count--;
		break;
	}
	elsebreak;
}
/*从Map[row][col]往右找,统计player的数量*/
for (int i = 1; i <= end; i++)
{
	if (arr[0][begin + i] == player)
	{
		count++;
	}
	elseif (arr[0][begin + i] == -player)
	{
		if (count < 5)
			count--;
		break;
	}
	elsebreak;
}
grade[0] = CountScore(count);	//根据player棋子数量统计分数

在这里我将专业术语里面的冲四和活三的权重认为是等同的,所以当坐左边或最右边有异类棋子时权重减一。

本来就写的不是很好这个AI,所以一切从简。

02

评分

因为一切从简,所以评分规则也是异常的简单。

int CountScore(int num)
{
	if (num >= 5)	//五子
		return50000;
	if (num == 4)	//四子
		return4320;
	if (num == 3)	//三子
		return720;
	if (num == 2)	//二子
		return120;
	if (num == 1)	//一子
		return20;
	return0;
}

在分给出每一个方向的评分后我给出了一个综合得分,这个综合得分是分析四个方向给出最高分

/*给出综合得分*/
int max_score = 0;
for (int i = 0; i < 4; i++)
{
	if (max_score < grade[i])
	{
		max_score = grade[i];
	}
	elseif (max_score == grade[i])
	{
		max_score += grade[i];
	}
}

03

分析落子

分析黑棋落子点是在白棋下完之后,对每一个空白处评分。

//确保鼠标在棋盘区域
if (x >= 15 && x <= 465 && y >= 15 && y <= 465)
{
	//此处无子
	if (Map[(y - 30 + 15) / 30][(x - 30 + 15) / 30] == 0)
	{
		//下子,改变currentPos
		currentPos.X = (x - 30 + 15) / 30;
		currentPos.Y = (y - 30 + 15) / 30;
		//map赋值
		Map[currentPos.Y][currentPos.X] = 1;	//玩家白棋
		GameDraw();
		if (Game_Juge())
		{
			return;
		}
        }
}

白棋下完之后,计算黑棋落子可能得分和白棋下一步落子可能评分,也就是进攻和防守。

struct GRADE
{
	int m_x;
	int m_y;
	int m_score;
};
GRADE attack_grade[MAP_ROW][MAP_COL];	//攻击分数
GRADE define_grade[MAP_ROW][MAP_COL];	//防御分数
//计算得分
for (int row = 0; row < MAP_ROW; row++)
{
	for (int col = 0; col < MAP_COL; col++)
	{
		if (Map[row][col] == 0)
		{
			define_grade[row][col].m_x = attack_grade[row][col].m_x = col;
			define_grade[row][col].m_y = attack_grade[row][col].m_y = row;
			attack_grade[row][col].m_score = Game_score(row, col, -1);
			define_grade[row][col].m_score = Game_score(row, col, 1);
		}
		else
		{
			define_grade[row][col].m_x = attack_grade[row][col].m_x = col;
			define_grade[row][col].m_y = attack_grade[row][col].m_y = row;
			define_grade[row][col].m_score = attack_grade[row][col].m_score = 0;
		}
	}
}

给出评分后确定黑子的落子点,就是判断进攻还是防守

//计算黑白棋最佳落子点
for (int row = 0; row < MAP_ROW; row++)
{
	for (int col = 0; col < MAP_COL; col++)
	{
		if (MaxAttackScore.m_score < attack_grade[row][col].m_score)
		{
			MaxAttackScore.m_score = attack_grade[row][col].m_score;
			MaxAttackScore.m_x = attack_grade[row][col].m_x;
			MaxAttackScore.m_y = attack_grade[row][col].m_y;
		}
		if (MaxDefineScore.m_score < define_grade[row][col].m_score)
		{
			MaxDefineScore.m_score = define_grade[row][col].m_score;
			MaxDefineScore.m_x = define_grade[row][col].m_x;
			MaxDefineScore.m_y = define_grade[row][col].m_y;
		}
	}
}
//选择进攻	还是		防守一波(放手一搏)
if (MaxAttackScore.m_score >= MaxDefineScore.m_score)
{
	Map[MaxAttackScore.m_y][MaxAttackScore.m_x] = -1;
	currentPos.X = MaxAttackScore.m_x;
	currentPos.Y = MaxAttackScore.m_y;
}
elseif (MaxAttackScore.m_score < MaxDefineScore.m_score)
{
	Map[MaxDefineScore.m_y][MaxDefineScore.m_x] = -1;
	currentPos.X = MaxDefineScore.m_x;
	currentPos.Y = MaxDefineScore.m_y;
}
GameDraw();
//判断输赢
if (Game_Juge())
{
	return;
}

04

关于五子棋人机

这个AI只能说简单的实现了最基本的人机对战,很多方面因素我都没有考虑到,纯粹是自己看了几个AI实现的方法,再发挥下自己的想象力,七平八凑凑出来的,参考下我的思路即可,不要深究,毕竟失败是成功它妈。因为有些学校集训的时候会有五子棋AI的项目,我没有这个经历,考虑的方向或方法可能不对,我这就属于失败的产物,娱乐一下就好。如果以后有时间了我会改进下五子棋AI算法。

 

举报

相关推荐

0 条评论