C语言设计三子棋

1 游戏规则介绍

三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等1。用“井”字分出3×3的格子,双方轮流下棋子(可以用O或者X来区别),只要将自己的棋子连成直线就赢了2,游戏规则示例如图1所示。

游戏需要两个人,并遵守以下规则:
1)假定红方优先,双方交替下棋
2)每个格子只能放1个棋子
3)3个棋子在一条直线,即为胜利

在这里插入图片描述

图1 游戏规则示例

2 设计游戏基本框架

2.1 程序流程图

首先设计基本的框架,流程图如图2所示。
图2 程序流程图

图2 程序流程图

程序开始后,首先显示初始化菜单,然后进行输入选择,当输入为0时,游戏结束,当输入为1时,开始游戏,输入其他数字,则会提示输入错误,并进行重新选择。

2.2 程序框架设计

参考代码如下所示,游戏基本功能将在子函数play()中实现。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void init()//初始化函数
{
/***************************************
函数功能:
	输出初始化游戏启动菜单。
函数输入:
	无
函数输出:
	无
***************************************/
	printf("*********************\n");
	printf("*******三子棋********\n");
	printf("**1.play    0.exit***\n");
	printf("*********************\n");
}
void play()//玩游戏
{
/***************************************
函数功能:
	实现游戏功能
函数输入:
	无
函数输出:
	无
***************************************/

}
int main()
{
	int state = 0;
	init();//初始化
	loop: scanf("%d", &state);//输入选择状态
	switch (state)
	{
	case 0:
		printf("游戏结束。");
		break;
	case 1:
		printf("游戏开始:\n");
		play();//玩游戏
		break;
	default:
		printf("输错了,请重新输入:>");

		goto loop;
		break;
	}
	return 0;
}

2.3 程序测试结果

在这里插入图片描述

图3 程序流程图

可以看到程序运行后显示初始化菜单,当输入1,游戏开始,输入0,游戏结束,当输入其他(比如5或68时),会提示重新输入,第一步框架结构成功实现。

3 子函数实现:

下面开始实现游戏的功能,即完成play()函数。

3.1 子程序流程图

首先设计基本的框架,流程图如图4所示。

在这里插入图片描述

图4 子程序流程图

如图所示,首先进行初始化,然后选手下子,并在屏幕上打印棋盘,再判断是否分出胜负,并根据结果进行输出相应的结果。

3.2 程序代码

int play()//玩游戏
{
/***************************************
函数功能:
	实现游戏功能
函数输入:
	无
函数输出:
	0:表示游戏结束
***************************************/
/*-----------------初始化------------------------*/
	int red[3][3] = { 0 };//红方棋盘信息矩阵
	int blue[3][3] = { 0 };//蓝方棋盘信息矩阵
	int green[3][3] = { 0 };//棋盘总信息矩阵
	int mat[3][3] = { 0 };//用于判断的矩阵
	DYQP(red, blue);//显示初始棋盘
	int shift = 0;//切换选手(使两个人交替下棋)
	int state = 0;//鹿死谁手?(state用于储存棋局的结果)
/*---------------------------------------------*/
	while (1)
	{
		QSLZ(&shift, red, blue);//棋手落子
		DYQP(red, blue);//打印棋盘
		state = JGPD(&shift, red, blue);//结果判断
		switch (state)
		{
		case 0:
			printf("继续,注意:观棋不语\n");
			break;
		case 1:
			printf("和局\n");
			return 0;
		case 2:
			printf("红方胜\n");
			return 0;
		case 3:
			printf("蓝方胜\n");
			return 0;
		default://state
			printf("程序又出错了么(ಥ﹏ಥ)\n");
			return 0;//游戏中断
		}
	}
	return 0;
}

该程序用到了三个子函数,分别是

  • DYQP(red, blue);//打印棋盘程序函数
  • QSLZ (&shift, red, blue);//棋手落子程序函数
  • JGPD(&shift, red, blue);//结果判断程序函数

这三个会在后文实现,下面先讲一些游戏设计规则。

4 游戏设计规则

因为棋盘大小是3×3,所以可以将棋盘信息存储在一个3行3列的数组里。其中红方和蓝方的棋盘信息分开存储,便于结果检测。下面以图1的示例,展示棋盘信息存储的状况,如图5所示。
在这里插入图片描述

图5 棋盘信息存储展示

棋盘信息矩阵初始值皆为0,当一个位置落子后,相应的位置的值改为1。双方棋盘信息矩阵用来保证一个位置只能落一个棋子。棋盘的位置以坐标的形式确定,如图6所示。
在这里插入图片描述

图6 棋盘位置坐标

5剩余子函数实现

5.1 打印棋盘程序函数

程序代码:

void DYQP(int (*red)[size], int (*blue)[size])
{
	int i, j;
	printf("	0	1	2\n\n");
	for (i = 0; i < size; i++)
	{
		printf("%d", i);
		for (j = 0; j < size; j++)
		{
			if (red[i][j] == 1)
				printf("	O");
			else if (blue[i][j] == 1)
				printf("	X");
			else
				printf("	#");
		}
		printf("\n");
	}
}

红方的棋盘信息矩阵的值为1,则相应位置打印字符’O’, 蓝方的打印字符’X’,未落子的位置打印字符’#’。

5.2 棋手落子程序函数

程序代码:

void QSLZ(int* shift, int(*red)[size], int(*blue)[size], int(*green)[size])
{
/***************************************
函数功能:
	棋手落子,存储棋盘信息
函数输入:
	shift:(shift的值只能取0和1)
		=0,红方落子
		=1,蓝方落子
	red:红方棋盘信息
	blue:蓝方棋盘信息
	green:红蓝双方的信息
函数输出:
	无
***************************************/
	int x, y;
	switch (*shift)
	{
	case 0:
		do
		{
			printf("红方(O)请输入坐标:>");
			scanf("%d%d", &x, &y);
			if (x > 2 || y > 2)
				printf("坐标位置输入越界(ー00ー)\n");
			else if (green[x][y] == 1)
				printf("该位置已被人占(^_-)\n");
			else
				red[x][y] = 1;
		}while ((x > 2 || y > 2)||(green[x][y] == 1));
		green[x][y] = 1;
		break;
	case 1:
		do
		{
			printf("蓝方(X)请输入坐标:>");
			scanf("%d%d", &x, &y);
			if (x > 2 || y > 2)
				printf("坐标位置输入越界(ー00ー)\n");
			else if (green[x][y] == 1)
				printf("该位置已被人占(^_-)\n");
			else
				blue[x][y] = 1;
		} while ((x > 2 || y > 2) || (green[x][y] == 1));
			green[x][y] = 1;
		break;
	default :
		printf("出错了么(* ̄rǒ ̄)");
		break;
	}
}

红方先落子,当输入的坐标不再棋盘范围内,或该位置被占,会有相应的提示,并且要求重新输入。

5.3 结果判断程序函数

程序代码:

int JGPD(int* shift, int (*red)[size], int (*blue)[size])//结果判断
{
	switch (*shift)
	{
	case 0:
		if(test(red) == 1)
		{
			return 1;//平局
		}
		else if (test(red) == 0)
		{
			return 2;//红胜
		}
		else
		{
			*shift = 1;//红方下完,转换成对手下棋状态
			return 0;//继续战斗
		}
		break;
	case 1:
		if (test(blue) == 0)
		{
			return 3;
		}
		else
		{
			*shift = 0;//蓝方下完,转换成对手下棋状态
			return 0;
		}
		break;
	default:
		return 0;
		break;
	}
}

平局输出1,红胜输出2,蓝胜输出3,未分出胜负则输出0。里面用到了胜利检测函数test(),其代码如下所示:

int test(int (*arr)[size])
{
	/***************************************
	函数功能:
		判断棋盘结果
	函数输入:
		arr:
			=red,红方棋盘判断
			=blue,蓝方棋盘判断
	***************************************/
	int i, j;
	int a = 0;
	int b = 0;
	int c = 0;
	int d = 0;
	int count = 0;
	for (i = 0; i < size; i++)//(行列每次检测三次)
	{
		for (j = 0; j < size; j++)
		{
			if (arr[j][i])//列检测
				a += 1;
			if (arr[i][j])
			{
				b += 1;//行检测
				count ++;// 和局判断
			}	
			if (i == 0)//对角线只需检测一次
			{
				c += arr[j][j];//主对角线检测
				d += (*arr)[2 * (j + 1)];//副对角线检测
			}
		}
		if (a == 3 || b == 3 || c == 3 || d == 3)
		{
			return 0;//返回0就是胜利
		}
		else
		{
			a = 0;//清零,为下一列检测做准备
			b = 0;
			//c = 0;	
			//d = 0;			
		}
	}
	if (count == 5)//当count等于5时,说明平局。该检测针对红方,因为红方为先手,当红方棋子达到5个时,则为平局
	{
		return 1;
	}
	else
	{
		return 2;
	}

}

6 总代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#define size 3
void init()//初始化函数
{
/***************************************
函数功能:
	输出初始化游戏启动菜单。
函数输入:
	无
函数输出:
	无
***************************************/
	printf("*********************\n");
	printf("*******三子棋********\n");
	printf("**1.play    0.exit***\n");
	printf("*********************\n");
}
int test(int (*arr)[size])
{
	/***************************************
	函数功能:
		判断棋盘结果
	函数输入:
		arr:
			=red,红方棋盘判断
			=blue,蓝方棋盘判断
	函数输出:
		无
	***************************************/
	int i, j;
	int a = 0;
	int b = 0;
	int c = 0;
	int d = 0;
	int count = 0;
	for (i = 0; i < size; i++)//(行列每次检测三次)
	{
		for (j = 0; j < size; j++)
		{
			if (arr[j][i])//列检测
				a += 1;
			if (arr[i][j])
			{
				b += 1;//行检测
				count ++;// 和局判断
			}	
			if (i == 0)//对角线只需检测一次
			{
				c += arr[j][j];//主对角线检测
				d += (*arr)[2 * (j + 1)];//副对角线检测
			}
		}
		if (a == 3 || b == 3 || c == 3 || d == 3)
		{
			return 0;//返回0就是胜利
		}
		else
		{
			a = 0;//清零,为下一列检测做准备
			b = 0;
			//c = 0;	
			//d = 0;			
		}
	}
	if (count == 5)//当count等于5时,说明平局。该检测针对红方,因为红方为先手,当红方棋子达到5个时,则为平局
	{
		return 1;
	}
	else
	{
		return 2;
	}

}
int JGPD(int* shift, int (*red)[size], int (*blue)[size])//结果判断
{
	switch (*shift)
	{
	case 0:
		if(test(red) == 1)
		{
			return 1;//平局
		}
		else if (test(red) == 0)
		{
			return 2;//红胜
		}
		else
		{
			*shift = 1;//红方下完,转换成对手下棋状态
			return 0;//继续战斗
		}
		break;
	case 1:
		if (test(blue) == 0)
		{
			return 3;
		}
		else
		{
			*shift = 0;//蓝方下完,转换成对手下棋状态
			return 0;
		}
		break;
	default:
		return 0;
		break;
	}
}
void QSLZ(int* shift, int(*red)[size], int(*blue)[size], int(*green)[size])
{
/***************************************
函数功能:
	棋手落子,存储棋盘信息
函数输入:
	shift:(shift的值只能取0和1)
		=0,红方落子
		=1,蓝方落子
	red:红方棋盘信息
	blue:蓝方棋盘信息
	green:红蓝双方的信息
函数输出:
	无
***************************************/
	int x, y;
	switch (*shift)
	{
	case 0:
		do
		{
			printf("红方(O)请输入坐标:>");
			scanf("%d%d", &x, &y);
			if (x > 2 || y > 2)
				printf("坐标位置输入越界(ー00ー)\n");
			else if (green[x][y] == 1)
				printf("该位置已被人占(^_-)\n");
			else
				red[x][y] = 1;
		}while ((x > 2 || y > 2)||(green[x][y] == 1));
		green[x][y] = 1;
		break;
	case 1:
		do
		{
			printf("蓝方(X)请输入坐标:>");
			scanf("%d%d", &x, &y);
			if (x > 2 || y > 2)
				printf("坐标位置输入越界(ー00ー)\n");
			else if (green[x][y] == 1)
				printf("该位置已被人占(^_-)\n");
			else
				blue[x][y] = 1;
		} while ((x > 2 || y > 2) || (green[x][y] == 1));
			green[x][y] = 1;
		break;
	default :
		printf("出错了么(* ̄rǒ ̄)");
		break;
	}
}
void DYQP(int (*red)[size], int (*blue)[size])//打印棋盘
{
	int i, j;
	printf("	0	1	2\n\n");
	for (i = 0; i < size; i++)
	{
		printf("%d", i);
		for (j = 0; j < size; j++)
		{
			if (red[i][j] == 1)
				printf("	O");
			else if (blue[i][j] == 1)
				printf("	X");
			else
				printf("	#");
		}
		printf("\n");
	}

	//printf("    |    |    \n");
	//printf("    |    |    \n");
	//printf("————————\n");
	//printf("    |    |    \n");
	//printf("    |    |    \n");
	//printf("————————\n");
	//printf("    |    |    \n");
	//printf("    |    |    \n");
}
int play()//玩游戏
{
/***************************************
函数功能:
	实现游戏功能
函数输入:
	无
函数输出:
	0:表示游戏结束
***************************************/
/*-----------------初始化------------------------*/
	int red[3][3] = { 0 };//红方棋盘信息矩阵
	int blue[3][3] = { 0 };//蓝方棋盘信息矩阵
	int green[3][3] = { 0 };//棋盘总信息矩阵
	int mat[3][3] = { 0 };//用于判断的矩阵
	DYQP(red, blue);//显示初始棋盘
	int shift = 0;//切换选手(使两个人交替下棋)
	int state = 0;//鹿死谁手?(state用于储存棋局的结果)
/*---------------------------------------------*/
	while (1)
	{
		QSLZ(&shift, red, blue, green);//棋手落子
		DYQP(red, blue);//打印棋盘
		state = JGPD(&shift, red, blue);//结果判断
		switch (state)
		{
		case 0:
			printf("继续,注意:观棋不语\n");
			break;
		case 1:
			printf("和局\n");
			return 0;
		case 2:
			printf("红方胜\n");
			return 0;
		case 3:
			printf("蓝方胜\n");
			return 0;
		default://state
			printf("程序又出错了么(ಥ﹏ಥ)\n");
			return 0;//游戏中断
		}
	}
	return 0;
}
int main()
{
	int state = 0;
	init();//初始化菜单
	loop: scanf("%d", &state);//输入选择状态
	switch (state)
	{
	case 0:
		printf("游戏结束。");
		break;
	case 1:
		printf("游戏开始:\n");
		play();//玩游戏
		break;
	default:
		printf("输错了,请重新输入:>");

		goto loop;
		break;
	}
	return 0;
}

6.1 运行结果

在这里插入图片描述

图7 运行结果

总结

代码还有待改进的地方,以后还会继续改进。如果你有改进的想法可以告诉我,我试着实现。


参考资料:


  1. https://baike.baidu.com/item/%E4%B8%89%E5%AD%90%E6%A3%8B/669077?fr=aladdin ↩︎

  2. 三子棋游戏,小时候的温馨记忆,看看你能放几个子? ↩︎

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值