【课堂练习】五子棋逻辑代码

课堂上完成的五子棋逻辑代码,主要功能如下

1:绘制地图

使用一个16*16的二维数组代表地图,X表示黑子,O表示白子,没有棋子的地方用*表示,由于坐标范围不超过128,所以使用了char数据类型足以

2:下棋

通过控制台输入坐标,梅花间竹的给二维数组相应的下标的元素赋值

3:判断胜负

最麻烦的功能,最简单的方法是葱二维数组的第一个元素开始遍历,通过对应关系找出是否存在有5个连续的颜色相同的棋子。但身为一个爱偷懒的程序员,我是不会采用这么耗费时间和麻烦的办法的。

在这里我主要用4个函数,通过下棋的坐标,分别判断该坐标的纵向、横向、左上到右下和右上到左下这四个方向是否存在5个连续的棋子。本来打算用一个函数实现的,但逻辑思维跟不上,所以只好采用4个函数来计算。


代码如下

/*
   项目名称:控制台版五子棋游戏
   作    者:
   所 有 者:
   版    本:v1.0

   项目功能:要求实现支持两人对战的游戏

   备注:
		X是黑子	
		O是白子
*/

#include <stdio.h>

char who;										//0表示黑子下,1表示白子下
unsigned char g_MAP[16][16];					//用一个二维数组表示地图

void show_map(void);							//显示地图
char play_chess(void);							//下棋
char is_true(char who);							//判断下棋的位置是否正确
char is_win(char row, char col, char* count);	//判断胜负

/*********************************************************************************************************************************/

/*
	把用户输入的下棋坐标传进以下四个函数,采用递归的方式判断是否有5个连续相同颜色的棋子
	用up函数做例子,如果用户下的是黑子,那黑子的坐标传进up函数后,up判断该坐标上方是否有黑子,有的话继续往上找
	如果超出棋盘,或者上方不再是黑子的时候,函数会以最上方的黑子坐标做参照,计算出下方连续的黑子数(包含最上方的黑子),返回给函数
	如果返回的是5,证明有5个连续的黑子,黑子胜

	up_left		函数能找出相邻的最左上方的棋子,
	left		函数能找出相邻的最左方的棋子,
	up_right	函数能找出相邻的最右上方的棋子;
	up			函数能找出相邻的最上方的棋子

*/
char up(char row, char col);
char up_left(char row, char col);
char up_right(char row, char col);
char left(char row, char col);

/**********************************************************************************************************************************/


int main(void)
{
	char wind = 1;								//判断游戏是否结束
	while (wind)
	{
		system("clear");
		show_map();
		if (5 == play_chess())					//下棋函数返回5,证明已经有5个相邻的同颜色棋子
		{
			wind = 0;
			system("clear");
			show_map();
			if (1 == who)						//判断哪个颜色获胜
			{
				printf("黑子胜,结束游戏\n");
			}
			else
			{
				printf("白子胜, 结束游戏\n");
			}
		}

	}

	return 0;
}

/************************************************************************************************************************************************/

//显示地图
void show_map()
{
	int i = 0;
	int j = 0;
	printf("  ");
	//打印棋盘的上方提示的横标
	for (i = 0; i < 16; i++)			
	{
		printf("%x ", i);
	}
	printf("\n");
	//打印棋盘,和棋子
	for (i = 0; i < 16; i++)			
	{
		printf("%x ", i);
		for (j = 0; j < 16; j++)
		{
			if (0 == g_MAP[i][j])
			{
				printf("* ");
				continue;
			}
			printf("%c ", g_MAP[i][j]);
		}
		printf("\n");
	}
}

//下棋函数
char play_chess(void)
{
	/*
	    res的返回值是相邻棋子数最多的方向的相邻棋子个数(包括刚下的棋子)
		res == 0,代表棋子没下到棋盘上,或者下到有棋子的地方 
	*/
	char res;
	if (0 == who)
	{
		printf("黑方请下棋:");
		//黑子下棋,无效坐标重新下
		while (0 == (res = is_true(who)));
		//下子成功后who++,代表到白子下
		who++;
	}
	else
	{
		printf("白方请下棋:");
		while (0 == (res = is_true(who)));
		//下子成功后who--,代表到黑子下
		who--;
	}
	return res;
}

//输入棋子的坐标,并判断是否有效坐标
char is_true(char who)
{
	char row, col;
	char i = 0;
	scanf("%hhd%hhd", &row, &col);
	//避免不合法的输入,清空缓冲区
	scanf("%*[^\n]");
	scanf("%*c");
	//判断坐标是否合法
	if (row > 16 || col > 16 || row < 0 || col < 0 || (g_MAP[row][col] != 0))
	{	
		printf("请输入正确坐标:");
		return 0;
	}

	//如果是黑子下子的话,赋值为'x',白子的话赋值位'O'
	g_MAP[row][col] = (who == 0) ? 'X' : 'O';
	//使用4个变量,记录4个方向相邻的棋子数
	char up1 = up(row, col);
	char left1 = left(row, col);
	char up_left1 = up_left(row, col);
	char up_right1 = up_right(row, col);

	//把上面4个变量加入数组中
	char arr[] = {up1, left1, up_left1, up_right1};
	char max = arr[0];
	//选出相邻棋子数最多的方向的相邻棋子数目作为返回值
	for (i = 1; i < 4; i++)
	{
		max = arr[i] > max ? arr[i] : max; 
	}
	return max;
}

//计算纵向相同颜色的连续棋子数目
char up(char row, char col)
{
	//超出棋盘,返回-1
	if (row > 15 || row < 0)
	{
		return -1;
	}
	//如果上方还是相同的棋子,继续递归
	if (g_MAP[row - 1][col] == g_MAP[row][col])
	{
		return up(row - 1, col);
	}
	//如果为边界上的棋子,或上方不再有相同颜色的棋子,而且距离下方边界还有4个格子以上的位置,则条件为真
	else if (row - 2 == -1 || (g_MAP[row - 1][col] != g_MAP[row][col] && row + 4 < 16))
	{
		char i = 0;
		//计算下方相同颜色连续的棋子数量,由于要包含第一个棋子,所以循环从1开始
		for (i = 1; i < 5; i++)
		{
			//如果下方不是相同颜色的棋子或者没有棋子的话,循环结束
			if (g_MAP[row + i][col] != g_MAP[row][col])
			{
				break;
			}
		}
		return i;
	}
}
	
//计算横向相同颜色的连续棋子数目
char left(char row, char col)
{
	if (col > 15 || col < 0)
	{
		return -1;
	}
	if (g_MAP[row][col - 1] == g_MAP[row][col])
	{
		return left(row, col - 1);
	}
	else if ((col - 2) == -1 || (g_MAP[row][col - 1] != g_MAP[row][col] && col + 4 < 16))
	{
		char i = 0;
		for (i = 1; i < 5; i++)
		{
			if (g_MAP[row][col + i] != g_MAP[row][col])
			{
				break;
			}
		}
		return i;
	}
}

//计算左上到右下相同颜色的连续棋子数目
char up_left(char row, char col)
{
	if (row > 15 || row < 0 || col > 15 || col < 0)
	{
		return -1;
	}
	if (g_MAP[row - 1][col - 1] == g_MAP[row][col])
	{
		return up_left(row - 1, col - 1);
	}
	else if (((row - 2) == -1 || (col - 2) == -1) || (g_MAP[row - 1][col - 1] != g_MAP[row][col] && row + 4 < 16 && col + 4 < 16))
	{
		char i = 0;
		for (i = 1; i < 5; i++)
		{
			if (g_MAP[row + i][col + i] != g_MAP[row][col])
			{
				break;
			}
		}
		return i;
	}
}

//计算右上到左下相同颜色的连续棋子数目
char up_right(char row, char col)
{
	if (row > 15 || row < 0 || col > 15 || col < 0)
	{
		return -1;
	}
	if (g_MAP[row - 1][col + 1] == g_MAP[row][col])
	{
		return up_right(row - 1, col + 1);
	}
	else if (((row - 2) == -1 || (col + 2) == 16) || (g_MAP[row - 1][col + 1] != g_MAP[row][col] && row + 4 < 16 && col - 4 > 0))
	{
		char i = 0;
		for (i = 1; i < 5; i++)
		{
			if (g_MAP[row + i][col - i] != g_MAP[row][col])
			{
				break;
			}
		}
		return i;
	}
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值