三子棋游戏的实现

前言

新人发文,可能有什么照顾不周的地方,请大伙多多关照!

一、三子棋是什么?

在写三子棋这个游戏之前,我们首先要知道三子棋是一个什么样的游戏。
在一定数量的格子中,画出X和O,三个字符链接到一起的时候游戏胜利
请添加图片描述
上面的图片便是三子棋的一个小长假,接下来让我们看看实现这个游戏需要什么样子的代码

二、代码的实现

1. 文件的创建

为了使检查bug更加的方便,我们这次使用三个文件来共同完成这一个小游戏,我创建的三个文件分别是

main.c

game.c

game.h

其中main.c文件中存放的是我的主函数和游戏的主要实现内容

game.h文件中存放的是我关于全局常量的定义,和一些函数的声明

而最后game.c文件中存放的是游戏函数的实现过程

2.游戏菜单的打印

首先,我们需要创建一个main函数,承担我们的接下来的代码
然后我们创建一个test函数来存放我们的主要内容(为了保持main函数的整洁)

int main()
{
	test();//调用主要函数,接下来的文件会在这里完成


	return 0;
}

为了玩游戏,我们首先需要打印一个可视化的游戏菜单,方便玩家对游戏进行操作。
为此,我们在test函数中调用menu函数
这一步很简单,只需要用到printf函数可以了
代码如下:

void menu()
{
	//应该先打印菜单
	printf("********************\n");
	printf("******1. game ******\n");
	printf("******0. exit*******\n");
	printf("********************\n");

}

由于只承担打印的作用,所以我们将返回类型设置为void
此时的test函数

void test()
{
	menu():
}

3.游戏选择部分的代码

对于这个部分,要实现一个游戏。我们此时就需要一个do…while循环,于是,再test中,我们就得到了如下代码

void test()
{
	//我们此时需要一个随机数
	srand((unsigned int)time(NULL));//这个再之后会讲解为什么插入的
	
	//需要打印游戏菜单
	menu();
	//应该设计为循环输入

	int i = 0;
	
	do
	{
		printf("请选择 》");
		scanf("%d", &i);
		switch (i)
		{
		case 1:
			printf("开始游戏\n");
			//接下来需要让人下棋
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;

		default:
			printf("请重新选择\n");
			break;


		}

	} while (i);


}

根据menu函数来看,继续游戏是1,退出是0.正好符合了c语言的真假判断标准,所以,把i放到while循环的判断部分,很巧妙的一个方法。

4.game()函数的实现

在我们有了整个主体的操作内容之后,我们需要让游戏跑起来。所以,我们创建一个game()函数,因为我们写的游戏是一个三子棋游戏,所以我们需要一个棋盘。棋盘就需要创建一个二维数组来实现,arr[3][3]。
此时写3 3的话,虽然简单,但是实际上看,却是把代码写死了,于是,我们在game .h定义两个常量

#define HANG 3
#define LIE 3

但是在这个数组中,默认的所有数字是0,所以我们需要对其进行初始化。我这里初始化为了‘ ’。
具体代码如下:
在game.h中

//对数组进行初始化为‘ ’
void spacing(char arr[HANG][LIE], int hang, int lie);

在 game.c 中

void spacing(char arr[HANG][LIE], int hang, int lie)
{
	int i = 0;
	for (i = 0; i < hang; i++)
	{
		int j = 0;
		for (j = 0; j < lie; j++)
		{
			arr[i][j] = ' ';
		}
	}

}

在对数组进行初始化完成之后,我们需要将其打印出来,所以我们创建一个打印函数。但是打印不能只打印数组,因为数组现在的内容是空格,打印出来看不到的。所以我们需要在这个附近加上分隔符

void print(char arr[HANG][LIE], int hang, int lie);

在game.c 中对应的函数为

void print(char arr[HANG][LIE], int hang, int lie)
{
	//打印的棋盘是需要分割符的
	int i = 0;
	for (i = 0; i < hang; i++)
	{
		int j = 0;
		for (j = 0; j < lie; j++)
		{
			printf(" %c ",arr[i][j]);
			if (j < lie - 1)
			{
				printf("|");
			}
			
		
		
		}
		printf("\n");
		if(i < hang - 1)
		{
			for (j = 0; j < lie; j++)//在每个for循环中j都会重置的
			{

				printf("___");//打印下划线
				if (j < lie - 1)
				{
					printf("|");//除了最后一个字符不打印 | 之外,都要打印,所以需要if来判断
				}
			}
		}
		printf("\n");
		
	}
}

这个时候,打印出来的棋盘为
请添加图片描述

5.玩家下棋

有了棋盘之后,我们就要开始下棋了,咱们让玩家下的棋子为‘ * ’。让玩家输入坐标就好,那么,我们创建的是一个数组,获取坐标之后,首先就需要进行越界检查。由于一般的玩家是不知道数组的第一个下表是从0开始的,所以,咱们获取的坐标就一定是一个在1~hang or 1~ lie 的数字,所以在放入数组的时候需要对其坐标进行 -1.最后,我们需要检测下棋的位置是否有别的的棋子,如果有的话,就需要对其进行查重检查。
在game.h中的代码如下

//玩家走棋子
void player(char arr[HANG][LIE], int hang, int lie);

在game.c中的代码文件如下

void player(char arr[HANG][LIE], int hang, int lie)//咱们让玩家走*
{
	printf("请输入坐标\n");
	while (1)
	{


		int i, j;
		scanf("%d %d", &i,&j);//这里我不小心把本应该的空格达成了,,所以导致测试老是出现错误,写代码还是需要更加的细心才行呢
		//i = i - 1;
		//j = j - 1;
		//要做一个占位检查,还要检查数字是否合法


		if (i >= 1 && i <= hang && j >= 1 && j <= lie)
		{
			if (arr[i -1][j - 1] != ' ')
			{
				printf("这个地方已经有棋子啦!重选一个吧!\n");
			}
			else
			{
				arr[i -1 ][j - 1] = '*';
				break;
			}
		}
		else
		{
			printf("坐标输入错误啦!重新输入一个吧\n");
		}
	}
}

6.电脑下棋

在玩家进行落子之后,需要电脑进行落子,由于本人的技术水平不到位,所以只能通过随机数来实现电脑落子,没法让电脑智能下棋。在之后如果有研究成果的话会发出来的。
使用随机数我们需要两个函数,一个是srand(),另一个是rand()
还需要两个头文件,由于咱们的两个.c文件中都引用了game.h,所以咱们在game.h中放入这两个头文件.

#include<stdlib.h>
#include<time.h>

然后srand函数,放到test()函数中

srand((unsigned int)time(NULL));

由于time()的返回类型为time_t,所以我们使用强制类型转换为int,然后给time一个空指针。
电脑落子的方法与玩家落子的方法大同小异,都需要进行占位检查
在game.h的代码为

void computer(char arr[HANG][LIE], int hang, int lie);

在game.c中的代码为

void computer(char arr[HANG][LIE], int hang, int lie)
{
	//可以通过随机数来获得走的地方,那么就需要调用时间戳
	//咱们让电脑下一个#
	printf("电脑行动\n");
	Sleep(1300);
	while (1)
	{
		int i = rand() % hang;
		int j = rand() % lie;
		if (arr[i][j] == ' ')
		{
			arr[i][j] = '#';
			break;
		}

	}
}

我这里还使用了一个sleep函数,让电脑睡一会儿,感觉更有意思(笑)

7.输赢判断

在完成了所有步骤之后,我们迎来了输赢判断的步骤
这里我有一件很可惜的事情,在之前的所有代码中,都没有写死,无论是棋盘大小和打印方法都可变,唯独在输赢判断,由于自身能力不足,所以只好写死了,我尝试的代码放在下面,待有朝一日会优化的

char arr2[HANG * LIE];//玩家数组
	char arr3[HANG * LIE];//电脑数组
	int n = 0;
	int m = 0;
	for (int i = 0; i < hang; i++)
	{
		int j = 0;
		for (j = 0; j < lie; j++)
		{
			if (arr[i][j] == '*')
			{
				arr2[n] = i;
				arr2[n + 1] = j;
				n = n + 2;
			}
			else if (arr[i][j] == '#')
			{
				arr3[m] = i;
				arr3[m + 1] = j;
				m = m + 2;
			}
		}
	}
	int w = 0;
	for (w = 0; w < hang * lie; w=w+2)
	{
		//人
		if (arr2[w] == arr2[w + 2] == arr2[w + 4] && arr2[w] + 2 == arr2[w + 3] + 1 == arr2[w + 5])
		{
			return '*';
		}
		if (arr2[w] + 2 == arr2[w + 1] + 2 == arr2[w + 2] + 1 == arr2[w + 3] + 1 == arr2[w + 4] == arr2[w + 5])
		{
			return '*';
		}
		if (arr2[w] == arr2[w + 5] && arr2[w + 1] == arr2[w + 4] && arr2[w + 2] == arr2[w + 3] && arr2[w] != 0)
		{
			return '*';
		}
		//电脑
		if (arr3[w] == arr3[w + 2] == arr3[w + 4] && arr3[w] + 2 == arr3[w + 3] + 1 == arr3[w + 5] )
		{
			return '#';
		}
		if (arr3[w] + 2 == arr3[w + 1] + 2 == arr3[w + 2] + 1 == arr3[w + 3] + 1 == arr3[w + 4] == arr3[w + 5] )
		{
			return '#';
		}
		if (arr3[w] == arr3[w + 5] && arr3[w + 1] == arr3[w + 4] && arr3[w + 2] == arr3[w + 3] && arr3[w] != 0)
		{
			return '#';
		}
	
	}

好,接下来我们来说这段代码的实现。
对于输赢来说,我们有四种情况:
1.玩家赢了(*)
2.电脑赢了(#)
3.平局(f)
4.继续(t)
我们要判断这四个情况,那么,我们写一个win函数,其中,我们通过棋盘是否满了来判断是否继续,所以,我们在game.c函数中嵌套一个full函数,full函数的代码如下

int full(char arr[HANG][LIE], int hang, int lie)
{
	for (int i = 0; i < hang; i++)
	{
		int j = 0;
		for (j = 0; j < lie; j++)
		{
			if (arr[i][j] == ' ')
			{
				return 1;
			}
		
		}
	}
	return 0;
}//判断棋盘是否放满的函数

而在win函数中对应的值为

int l = full(arr, hang, lie);
	if (l == 0)//这里出现过一次错误,==千万不要写成=了
		return 'f';
	else
		return 't';

接下来我们只需要通过穷举方法来判断胜负就好了
在game.h的代码如下

char win(char arr[HANG][LIE], int hang, int lie);

(因为我们是需要返回值的,所以类型设置为char)
在game.c的代码如下

char win(char arr[HANG][LIE], int hang, int lie)
{
	
	//判断输赢
	//检查 行
	for (int i = 0; i < hang; i++)
	{
		if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
		{
			return arr[i][0];
		}
	}
	//检查列

	for (int i = 0; i < lie; i++)
	{
		if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[2][i] != ' ')
		{
			return arr[0][i];
		}
	}
	
	
	//对角线
	if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[2][2] != ' ')
	{
		return arr[0][0];
	}
	if (arr[0][3] == arr[2][2] && arr[2][2] == arr[3][1] && arr[2][2] != ' ')
	{
		return arr[2][2];
	}
	

	
	//,判断棋盘是否摆满了
	int l = full(arr, hang, lie);
	if (l == 0)//这里出现过一次错误,==千万不要写成=了
		return 'f';
	else
		return 't';
}

在main.c文件中的game()封装为

void game()
{
	char ret = 0;
	//目标是写一个下井字棋棋小游戏,首先需要创建一个二维数组
	char arr[HANG][LIE];
	//接下来需要对数组内容进行初始化
	spacing(arr, HANG, LIE);
	//打印棋盘,使用函数print
	print(arr, HANG, LIE);
	while (1)
	{


		//需要让玩家行走
		player(arr, HANG, LIE);
		print(arr, HANG, LIE);
		//我们此时还需要一个函数来判断输赢 假设t为继续,#为电脑赢了,*为人赢了,f为平局
		ret = win(arr,HANG,LIE);
		if (ret != 't')
			break;
		//让电脑行走,写随机数
		ret = win(arr, HANG, LIE);
		if (ret != 't')
			break;
		computer(arr, HANG, LIE);
		print(arr, HANG, LIE);
		
	}
	if (ret == '*')
		printf("你赢了\n");
	else if (ret == '#')
		printf("你输了\n");
	else if (ret == 'f')
		printf("平局\n");
	menu();

}

在这里我们就结束了这个游戏
希望这个文章能对你有所帮助

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值