黑白棋游戏源代码分析

 

 

游戏规则:

在一个8x8的棋盘有两个玩家,他们轮流放入分别放入白色和黑色的棋子。

当一个玩家在空棋子的位置放入一个棋子,我们检查放入棋子的8个方向 上 下 左 右 左上 左下 右上 右下,如果这8个方向上有自己这方的棋子夹的全是对方的棋子,则对方的棋子将被吃掉,变成我方的棋子。

当旗盘中不能放入棋子的时候游戏结束。如下图,黑方先走,然后是白方走

 

有用户输入8x8旗盘的格局和哪一方先走,请编写一个程序输出哪一方最后能够赢得游戏,或是平局。

 

输入:

有一个8x8的旗盘(‘b’代表黑色的棋子,‘w’代表白色的棋子,’e’代表空棋子),之后输入谁先走。当输入”endofinpur”(没有了格局)时结束游戏;

在每一种格局里面,最多只有10个空棋子。

 

输出:

每一种格局都用一行输出赢的一方(黑方或是白方)或是平局。确定每一行都没有空棋子。

 

例如输入:

wwwwwwww

wwwwwwww

wwwwwwww

wwwwwwww

wwwwwwww

wwwwwwww

wwwwwwww

wwwwwwww

black

wwwwwwww

wwwwwwww

wwwwwwww

wwwwwwww

bbbbbbbb

bbbbbbbb

bbbbbbbb

bbbbbbbb

white

endofinput

 

输出:

White

Draw

 

 

 

源代码:

#include"stdio.h"
#include"string.h"
int  kong[10][2], kong_num = 0,    //kong[][]存储旗盘中所有空棋子的位置,kong_num存储空棋子的数目
     yidong[8][2]={{-1, -1},{-1, 0},{-1, 1},{0, 1},{1, 1},{1, 0},{1, -1},{0, -1}}; //yidong[][]存储移动的8个方向

void panduan(char qi[8][8]) //通过检查白棋个数判断黑白棋哪一方胜利
{
	/*white_num存储旗盘中的白棋个数*/
	int white_num = 0;      
	for(int i = 0; i < 8; i++)
		for(int j = 0; j < 8; j++)
			if(qi[i][j] == 'w')
				white_num++;
	if(white_num < 32)
		printf("\nBlack\n");
	else if(white_num == 32)
		printf("\nDraw\n");
	else
		printf("\nWhite\n");

}

void boyi(char qi[8][8], char first,char next )  //根据最优策略,求出当下旗的走法,first存储要走的旗帜,next存储被吃的棋子
{
	/*quan[]存储当前空棋子放入first旗帜后可以吃掉next旗帜的个数;max为可以被吃掉最多棋子个数的quan[]的位置;
	next_row,next_col分别为下一个棋子的行列号;times与yidong[j][]相乘就是某一方向上下一个要改变的旗帜偏移量;
	temp[]存储某个方向上将要改变的的旗帜*/
	int quan[10], max = 0, next_row, next_col, times;
	char temp[8];
	for(int i = 0; i < kong_num; i++)  //根据最优策略,求出能被吃掉最多棋子的空棋子的位置
	{
		quan[i] = 0;
		for(int j = 0; j < 8; j++)
		{
			next_row = kong[i][0] + yidong[j][0];  //下一个要吃掉的旗帜的行号
		    next_col = kong[i][1] + yidong[j][1];  //下一个要吃掉的棋子的列号
			times = 1;
			/*如果下一个要吃掉的棋子的位置没有溢出,并且下一个棋子要是被吃掉的棋子,将能被吃掉的棋子个数记录下来*/
			while(next_row < 8 && next_row >=0 && next_row < 8 && next_row >=0 && qi[next_row][next_col] == next)
			{
				    quan[i]++;
					times++;
				    next_row = kong[i][0] + times * yidong[j][0];
		            next_col = kong[i][1] + times * yidong[j][1];
			}
			/*如果这个方向上的棋子不能被吃掉,恢复这一方向上的棋子数去掉*/
			if(next_row >= 8 || next_row <0 || next_col >= 8 || next_col <0 || qi[next_row][next_col] != first)
				quan[i] = quan[i] - times + 1;
		}
		if(quan[i] > quan[max])  //求出能被吃掉最多棋子个数的,空棋子的位置
			max = i;
	}   
	qi[kong[max][0]][kong[max][1]] = first;
	for(int j = 0; j < 8; j++)//根据最优策略,将first棋子放入并更改棋盘上的格局
	{
		next_row = kong[max][0] + yidong[j][0];
		next_col = kong[max][1] + yidong[j][1];
	    times = 1;
		/*如果下一个要吃掉的棋子的位置没有溢出,并且下一个棋子要是被吃掉的棋子,将下一个棋子吃掉*/
		while(next_row < 8 && next_row >=0 && next_col < 8 && next_col >=0 && qi[next_row][next_col] == next)
		{
			temp[times] = qi[next_row][next_col];
			qi[next_row][next_col] = first;
			times++;
		    next_row = kong[max][0] + times * yidong[j][0];
		    next_col = kong[max][1] + times * yidong[j][1];
		}
		/*如果这个方向上的棋子不能被吃掉,恢复这一方向上的棋子原来的格局*/
		if(next_row >= 8 || next_row <0 || next_col >= 8 || next_col <0 || qi[next_row][next_col] != first)
		{
			for(i = 1;i < times; i++)
			{
				next_row = kong[max][0] + i * yidong[j][0];
		        next_col = kong[max][1] + i * yidong[j][1];
				qi[next_row][next_col] = temp[i];
			}
		}

	}
	for(int q = max; q < kong_num - 1; q++) //去掉存储空棋子中的 放入棋子的位子
	{
		kong[q][0] = kong[q + 1][0];
		kong[q][1] = kong[q + 1][1];
	}
	kong_num--;    
	/*
	printf("\n========\n");
	for(i = 0; i < 8; i++)
	{
		for(int j = 0; j < 8; j++)
			printf("%c",qi[i][j]);
		printf("\n");
	}
	*/
	if(kong_num == 0)//如果空棋子没有了,判断结果
		panduan(qi);
	else           //如果空棋子还,继续博弈
		boyi(qi, next, first);
}

void shuru()  //接收用户输入的黑白棋的的格局
{
	/*first存储判断黑白方先走的一个方的代码;qi[][]存放当前棋子的格局;
	row_1[]存放第一行输入的字符串;end[]存放结束字符串,judge[]存放先走的一方*/
	int first;
	char qi[8][8],row_1[11],end[11] = "endofinput", judge[6];
	while(1)
	{
		printf("\n请输入8行8列的黑白棋的旗盘局势:\nw 代表白棋\tb 代表黑棋\te 代表空\tendofinput 退出\n");
		gets(row_1);                //接收第一行的字符串
		if(strcmp(row_1,end) == 0)  //判断是否为结束提示语,如果是的则跳出循环
			break;
		else      
		{
			for(int r = 0; r < 8; r++)  //将第一行的棋子格局存储起来,并记录其中空棋子的位置
			{
				if(row_1[r] == 'e')
					{
						kong[kong_num][0] = 0;
				    	kong[kong_num][1] = r;
				    	kong_num++;
					}
				qi[0][r] = row_1[r];
			}
			for(int i = 1; i < 8; i++) //将 2-8 行的棋子格局存储起来,并记录其中空棋子的位置
			{
				for(int j = 0; j <8; j++)
				{
					scanf("%c", &qi[i][j]);
			    	if(qi[i][j] == 'e')
					{
						kong[kong_num][0] = i;
				    	kong[kong_num][1] = j;
				    	kong_num++;
					}
				}
			    getchar();
			}
			printf("\n请输入哪一方先走:white 白方先走,black 黑方先走\n");
		    gets(judge);  //判断哪一方先走
	     	if(kong_num != 0)
			{
				if(strcmp(judge,"white") == 0)
					boyi(qi, 'w', 'b');
			    else
				    boyi(qi, 'b', 'w');
			}
		    else
			     panduan(qi);
		}
	}
}
	

int main()
{
	shuru(); //输入棋盘的格局
	getchar();
	return 0;
}


 

解题思路:

这个游戏便是我们经常玩的一种黑白旗的游戏,由于它里面空的棋子最多为10个,那么我们可以用最优策略来下棋。即当将我方棋子放入空棋子的位置的时候能吃掉最多对方棋子数目的时候,此位置为最优解位置。

那么此游戏的程序可以分为3个阶段:

第一阶段:将旗盘的格局和先走的一方接收并将其存储起来。

第二阶段:根据输入的旗盘格局和先走的一方,用递归的方法对其进行博弈(当前走棋的

一方用最优策略进行走棋),直到旗盘里面没有空棋子为止。

第三阶段:通过检查白色棋子的个数(是否大于32或是等于32)判断哪一方获胜并将其

输出。

此游戏主要难在第二阶段的吃棋子的问题上面。首先要在第一阶段输入棋子格局的时候将空棋子所在的位置存储起来,然后第二个阶段的时候,在每一个空棋子的位置判断可吃棋子的个数。可吃棋子个数最多的位置就是当前最优位置,则在这个位置放入棋子,并吃掉对方的棋子。

而在此处,怎样吃棋子又是一个难点。可以把棋子的8个方向分开来判断,在某一个方向上,如果下一个棋子没有溢出,并且下一个棋子是对方的棋子,则将其吃掉。如果下一个棋子不是对方的棋子是自己的棋子,则这个方向上吃棋子结束,跳入到下一个方向。如果下一个棋子不是对方的棋子,是棋子溢出了或是空棋子,则将这一个方向上面吃掉的棋子还原。进入下一个方向吃棋子。如果8个方向的棋子的判断过了,那么吃棋子结束。 如果还有空棋子,那么递归轮到对方吃棋子。

 

 

欢迎大家转载,如有转载请注明文章来自:   http://blog.csdn.net/q345852047

 

你可能感兴趣的:(算法)