三子棋游戏的实现超详细讲解

      

目录

一、三子棋实现的初步思路

二、三子棋的基本框架的实现

三、三子棋游戏的具体实现

 四、总结

        哈喽,大家好,今天小编来为大家带来一个超详细三子棋游戏的讲解。

一、三子棋实现的初步思路

        想要实现三子棋游戏,我们会设定游戏的模式,第一点就是,我们需要用一个循环来实现游戏不退出,玩一次可以继续玩下一把。其次呢,我们需要多文件的形式来实现代码。

我们需要①test.c——测试游戏②game.c——实现游戏③game.h——游戏函数的声明

        简单为大家介绍之后,接下来让我们一起来学习如何用代码实现吧!

二、三子棋的基本框架的实现

        首先,我们这个三子棋的游戏逻辑是可以一直进行这个游戏,这里可以用循环来实现。因为一开始就要进行游戏一次,所以我们选择使用do ——while循环来实现这一步骤。循环进入,游戏开始,我们最开始打印一份游戏菜单;写一个函数来打印游戏菜单,打印完菜单之后,我们应该选择是玩游戏,或者是退出。这时我们可以使用一个switch语句,我们设定输入1,则是开始游戏,输入0,则是退出游戏,输入如果既不是1也不是0,那说明选错了,那就重新选择,当我们选择完后,最后都是break跳出switch,来到while,也就是循环判断条件,因为我们最开始说,只有输入0,是退出游戏,也就是跳出循环,输入其他数则重新开始,所以这时,我们可以直接把input放在判断部分即可,具体代码如下。

#include<stdio.h>
void menu()
{
	printf("**********************************\n");
	printf("**********   1.play     ***********\n");
	printf("**********   0.exit     **********\n");
	printf("**********************************\n");
	printf("**********************************\n");

}
int main()
{
	int input = 0;
	do
	{
		menu();//菜单
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("三子棋游戏\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:       //选的不是1也不是0,说明选错了
			printf("选择错误,请重新选择\n");
				break;
		}
	} while(input);
	return 0;
}

                现在我们运行一下如上代码,来看看是否达到我们想要的结果。这时我们游戏的基本框架就达到了。运行结果如下。

三、三子棋游戏的具体实现

        当我们基本框架写完之后,接下来我们来具体实现三子棋游戏的代码,当我们输入1之后,开始三子棋游戏,这时我们可以写一个game的函数,来进行游戏。紧接着我们来想想游戏是怎么玩的。首先我们需要打印棋盘,具体棋盘是什么样的呢,这里小编拿出个棋盘来供大家参考,如下图。

1、初始化数组

       根据图片我们可以看到,这是一个3×3的格子,而我们知道,我们每下一步之后,我们需要保留我们原来下的步骤,我们知道数组可以很好的保留数据,所以,这里就只需要一个3×3的二维数组即可,我们下棋的时候,我们一般采用字符(比如√,⭕,✳等等)来输入,所以我们需要定义一个二维字符数组即可。

        然后接下来我们知道,当我们在下棋的时候,这个3×3的棋盘里面应该是都看不见,是没有填充棋子的,这时需要我们把这9个位置打印成空格即可,未来在下棋的时候,只需要将空格换掉即可。也就是说,这里没下棋之前,数组中存放的是空格。我们需要初始化数组。当分析完毕后,接下来我们用代码来实现吧!

        首先,我们创建一个3×3的字符数组(board),我们会发现,如果我们想要把他初始成空格的,我们需要打出9个空格,这样会显得很麻烦,这里我们可以专门写一个函数(InitBoard)来将数组初始化成空格。这时我们需要把数组,以及行数和列数传参过去。我们最开始说了,我们在game.h中来声明函数,在game.c中来具体实现游戏函数。当我们在game.h中声明后,我们想在test.c中使用的,我们需要引用game.h这个头文件。具体代码如下。

         写到这里,我们会想到,当我们在后面打印棋盘的时候,我们会用的这个行和列,我们会写出一堆3,但是,如何我们想去玩更大的棋盘时,我们则需要很麻烦的把这些3换成更大的数,需要慢慢去修改。我们会发现很麻烦,这时有一个更好的办法,我们可以用define定义宏,直接定义行和列,在以后修改的时候就只需要在define这里更改就好了,会简单很多。代码如下。

         当我们初始化函数声明完之后,我们就来进行游戏的实现,我们将在game.c里面进行游戏函数的实现,当然我们这里也需要引用game.h这个头文件。

        接下来我们来初始化棋盘吧。我们这个函数的目标是要把这个数组全部变成空格,这时我们需要遍历这个数组即可。代码如下。

 2、打印棋盘

        当我们初始化完数组以后,我们接下来需要打印棋盘。那么我们这里需要再写一个函数,来打印棋盘。其实打印棋盘就是对数组进行改变,这时我们依然是需要把数组以及它的行和列传过去。然后我们依然和刚刚初始化棋盘一样,对函数在game.h中进行声明,然后在game.c中进行具体实现。

        如何打印棋盘呢,如下图,我们会发现,我们行与行之间有分割线,列与列之间也有分割线,那么我们就按照每行每行的来,第一行打印数据,第二行打印分割行,然后依次类推,其实打印数据的时候,我们需要空格来隔开,这样会使得我们的棋盘更好看一些。其次呢,我们最后一行的分割行是不需要的。这时我们只需要加上一个限制条件即可。前两行打印分割线,第三行则不会打印分割线。这时我们的棋盘就基本实现了。具体代码如下所示。

        其实上面这个打印,也是有问题的,当我们觉得棋盘不合适了,我想改成10×10的棋盘时,我们会发现,打印的结果会是10×3的棋盘,行没有问题,但是列有问题。因为我们在打印数据的时候 规定了只有三行。那么接下来我们需要优化一下棋盘的打印。

3、优化棋盘的打印

        借鉴前面的思路,我们发现在打印数据的时候,需要打印一个数据(也就是一个空格一个字符一个空格),然后打印一个竖着的分割线,只不过最后一行没有分割线嘛。这样我们可以把这一行拆开来打印,然后在给一个限制条件,使得不打印最后一个竖杠。同时我们的分割线也可以采取这样的方法和思路去打印。如下代码。

void DisyplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)//决定行数
	{
		int j = 0;
		for (j = 0; j < col; j++)//打印数据
		{
			printf(" %c ", board[i][j]);//第一个数据
			if(j<col-1)//限制条件,使最后
				printf("|");//打印完一个数据后打印竖杠
		}
		printf("\n");//每次打印完一行之后进行换行
		if (i < row - 1)//限制条件使得最后一行不打印分割线
		{
			int k = 0;
			for (k = 0; k < row; k++)
			{
				printf("---");
				if (k < col - 1)//最后一列不打印竖杠
					printf("|");
			}
			printf("\n");//打印一行之后进行换行
		}
	}
}

 这时我们运行一下来看看结果,这时不管你的行和列是多少,都能打印出来了。如下图所示。

 4、玩家下棋的实现

        下棋的时候,我们假设玩家先下棋,然后电脑在下棋,这时我们需要两个函数来实现这两个操作。我们发现下棋其实还是对数组进行改变,我们依然是将数组以及它的行和列传入进去。然后在game.h中声明,在game.c中实现。

        玩家是如何下棋的呢,其实就是找个地方放棋子。这时玩家需要找一个位置(坐标)进行落子,但是我们也应该判断一下玩家给的坐标是否是正确的。第一我们要判断的是玩家下的坐标行数和列数符不符合要求,其次要判断玩家所下的位置是否已经被占用,也就是说,只有是空格的时候,才可以下棋。如果输入的位置被占用,则提示,并且重新输入。具体代码如下。

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:\n");
	while (1)
	{
		printf("请输入下棋的坐标,中间使用空格>:");
		scanf("%d %d", &x, &y);//输入要下棋的位置
		if (x >= 1 && x <= row && y >= 1 && y <= col)//坐标合法
		{
			if (board[x-1][y-1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;//输入完之后,跳出循环,不能多次落子
			}
			else
			{
				printf("坐标被占用,不能落子,请重新落子:\n");
			}
		}
		else//坐标非法
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

5、电脑玩家下棋

        还是和上面一样,我们创建一个ComputerMove函数来实现电脑下棋,还是将数组以及它的行和列传过去,然后在game.h中进行声明,在game.c中进行实现。我们设定简单一点,设置电脑随机下棋。电脑落子是我们控制,所以我们直接采用数组下标即可,首先限定电脑下棋落子的范围,我们需要将电脑的落子控制在棋盘范围内,对应数组下标也就是row-1和col-1;因为电脑是随机下棋,所以我们需要使用rand函数,再将rand得到的值模row和col使得x,y的范围控制在0~row-1和0~col-1.使用rand函数我们需要调用srand,只需要调用一次,那就放在主函数中,传入time函数,放上空指针。当然使用srand函数和time函数都需要包含头文件stdlib.h以及time.h两个头文件。

        讲到这里,我们会发现我们每次写的时候都需要在game.c以及test.c中引用头文件,比如stdio.h头文件,我们需要在两个C文件中都引用头文件,其实引用头文件也是为了对函数进行声明,那么我们这里其实可以把所有的头文件全部放在game.h中,然后每次只需要在game.h中添加头文件即可。

        限定完落子范围后,我们还需要判断一下,在落子的时候,该位置是否已经有棋子了。如果没有,那就下入#号并跳出循环,如果有,那就继续生成随机坐标来落子。具体代码实现如下。

void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;//范围控制在row-1
	int y = 0;//范围控制在col-1
	printf("电脑下棋>:\n");
	//随机落子
	while (1)
	{
		x = rand() % row;//使得x范围在row-1
		y = rand() % col;//使得y范围在col-1
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}

}

        那么写到这里,我们的电脑下棋的实现似乎已经完成,但是我们仔细想一想,当我们开始下棋后,我们下一个棋子,电脑下一个棋子,当我们把最后一个格子下入棋子后(不管输赢),那么轮到电脑下棋了,此时已经没有空的格子了,那么电脑下棋就会死循环。那么下棋下到最后,会出现输赢的情况,然后结束这个游戏。

6、判断游戏输赢

        那在什么时候进行判断呢?在玩家下完棋之后需要判断输赢,电脑下完棋之后也一样需要判断输赢。那么我们依然这里需要写一个函数(IsWin)来判断输赢,把数组已经行与列传入函数,在game.h中进行声明,在game.c中进行实现。

        如何判断输赢呢,小编这里的想法是,在玩家和电脑下完之后进行判断,判断的结果有如下几种情况:①玩家获胜——返回“✳”②电脑获胜“——返回#”③平局——返回“Q”④继续下棋——返回“C”。那么我们这个函数的返回类型就是char。

        怎样才算是赢呢,那就是三个相等的字符组成一条线并且字符不能为空格。三行或者三列以及对角线。

        怎样才算平局呢,是不是前面下完棋之后,没有空格了,没有地方可以放棋子了,就算是平局了。那么这里我们需要写一个函数(IsFull)来判断棋盘是否已经下满了.

        当我们输赢和平局都判断完之后,依然没有结束,说明我们的棋盘还在继续。具体代码如下所示。

int IsFull(char board[ROW][COL], int row, int col)//判断棋盘是否满了
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}
//判断输赢
//1.玩家获胜——‘*’
//2.电脑获胜——‘#’
//3.平局———‘Q’
//继续——‘C’
char IsWin(char board[ROW][COL], int row, int col)
{
	//获胜
	int i = 0;
	for (i = 0; i < row; i++)//行
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
			return board[i][0];
	}
	for (i = 0; i < col; i++)//列
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
			return board[0][i];
	}
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
		return board[0][0];
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
		return board[0][0];
	//平局
	if (IsFull(board, row, col)==1)
	{
		return 'Q';
	}
	//继续
	return 'C';
}

         然后我们可以试着玩一把。具体效果如下图所示。

 四、总结

        好的,那么今天的三子棋到 这里就结束了,那么小编在这里为大家做个简单的总结,总的来说,我们的游戏的实现是多文件共同协作的,这样方便我们去调试,更改。其次呢,我们写的时候要逻辑清晰,边写边调试,以免最后写出一堆bug也很难找。最后,我们在写代码的时候要勇于去写bug,并且找bug,然后不断优化。其实这个三子棋游戏的代码还可以继续优化。那么小编在这里就不多讲解了,简单的三子棋已经完成。最后呢如果有哪里写的不好的地方,还请大家多多指点。如果觉得小编写的还不错的,那就留下关注和点赞,和小编一起学习吧!谢谢大家的观看。

 

  • 31
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 28
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

褪色~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值