C语言创建三子棋小游戏(可扩展棋盘)

       

目录

       

实现思路讲解:

代码内容

main函数内容

mune打印菜单函数

game()函数,存放游戏内容

       game()函数内容详解

        game.h头文件

        ChuShi()初始化函数

        PrintArr()打印函数

        PlayerMove()玩家移动函数

        ComputerMove()电脑移动函数

        IsWin()判断当前状况函数

        IsFull()判断是否填满函数

        全部代码

        text.c

        game.c

        game.h


实现思路讲解:

        首先我们要分装函数,新建两个源文件和一个头文件text.c用于实现游戏开始前的逻辑和测试。game.c用于实现游戏逻辑。game.h用于实现函数的声明。

         在text.c文件中创建main函数,在main函数中创建text函数,再在text函数中通过do.....while语句实现游戏的循环游玩。在简单创建一个menu函数用于打印我们的初始菜单栏。Menu函数要放在do...while语句中,每次循环都会打印。在text中要先定义一个input,input用于接收我们输入数字1表示进行游戏,0表示退出游戏,其他数字则会报错,为了实现这样的效果,我们需要在do...while语句中创建Switch case语句,case 1中放game函数,case2中放break,default表示其他情况,打印输入错误。最重要的部分是,在do while语句中,while的循环条件必须要是input,当我们输入非0常数时,while判断都为真,怎样都会返回继续循环,当我们输入0,跳出了Switch case语句中,但由于input=0,为假,会跳出游戏的循环,则结束游戏。

        注意,因为我们加了game.h文件,所以当我们用到printf等函数数时,要引用的头文件直接放在game.h中,后续在text.c和game.c文件中,只要在开头加上#include“game.h”就行。

代码内容

main函数内容

#include"game_3ziqi.h"

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		mune();
		printf("是否游玩(0/1)?\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
		default:
			printf("输入错误,请重新输入!\n");
		}
	} while (input);
	return 0;
}

mune打印菜单函数

void mune()
{
	printf("*************************\n");
	printf("*******  1.play  ********\n");
	printf("*******  0.exit  ********\n");
	printf("*************************\n");
}

game()函数,存放游戏内容

void game()
{
	char arr[ROW][COL] = {0};
	ChuShi(arr, ROW, COL);
	PrintArr(arr, ROW, COL);
	char ret = 'j';//判断游戏是否继续的条件
	while (1)
	{
		PlayerMove(arr, ROW, COL);
		PrintArr(arr, ROW, COL);
		ret = IsWin(arr, ROW, COL);
		if (ret != 'j')
		{
			break;
		}
		ComputerMove(arr, ROW, COL);
		PrintArr(arr, ROW, COL);
		ret=IsWin(arr, ROW, COL);
		if (ret != 'j')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家胜利\n");
	}
	if (ret == '#')
	{
		printf("电脑胜利\n");
	}
	if (ret == 'p')
	{
		printf("平局\n");
	}
}

       game()函数内容详解

        首先game函数只进行调用函数,而不定义函数,函数的声明放在game.h文件中,函数的定义(内容的实现)放在game.c文件中。然后我们就需要打game函数里的代码了。先定义一个char类型的二维数组作为棋盘,长为ROW,宽为COL,内容先给为0,。然后再game.h中define两个变量的大小为3。这样做的好处在于,若后续我们想修改长宽,可以在定义中直接修改,不用后续一个一个去改,减少了修改的工作量。

        注意:在game.h中要负责声明函数、定义棋盘格长宽、引用头文件。game.h文件如下:(其中ROW表示长,COL表示宽)

        game.h头文件
#include<stdio.h>//printf
#include<time.h>//time
#include<stdlib.h>//rand,srand

#define ROW 3
#define COL 3

//函数声明
//初始化棋盘
void ChuShi(char arr[ROW][COL], int row, int col);
//打印棋盘
void PrintArr(char arr[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char arr[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char arr[ROW][COL], int row, int col);
//判断胜利
char IsWin(char arr[ROW][COL], int row, int col);

        接着我们要给二维数组内加内容了。为防止数组中的内容不统一,我们先进行初始化数组,把数组内的每个元素都给上空格,方便我们前期我们后期的调用。具体操作为,先在text.c文件的game函数中,定义一个函数ChuShi(sanziqi,ROW,COL)在里面放上棋盘和长宽,再在game.h中声明这个函数  void chushi(char sanziqi[ROW][COL], int row, int col);

        (注意,声明的函数里row和col不能是大写,要不然会与之前定义的长宽相冲突,这里声明只是为了接收ROW和COL的值,当形参,并不是等于他俩),然后把声明的这串内容复制到game.c文件中,为其添加代码内容,实现功能。后续在game函数中加的其他函数皆是这样的操作。

        ChuShi()初始化函数
//初始化数组
void ChuShi(char arr[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < ROW; i++)
	{
		int j = 0;
		for (j = 0; j < COL; j++)
		{
			//把二维数组全部放空格清零
			arr[i][j] = ' ';
		}
	}
}

        把二维数组内容全部清空后,接着我们要打印棋盘格,在我们的想法中,棋盘格的样式应该如下:

 第一行里放可以存放字符的部分,在打印一行分割行;第二行一样,接着第三行只打印内容行,不打印分割行,其具体代码如下:

        PrintArr()打印函数
//打印棋盘
//   |   |   
//---|---|---
//   |   |   
//---|---|---
//   |   |   
void PrintArr(char arr[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 ",arr[i][j]);
			if (j < COL - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		//打印分割行
		for (j = 0; j < COL; j++)
		{
			//分割行只打印2列
			if (i < ROW - 1)
			{
				printf("---");
				if (j < COL - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

        打印完棋盘,接着我们要进行玩家下棋了。我们用PlayMove()函数来存放玩家下棋的代码。具体代码如下:

        PlayerMove()玩家移动函数
//玩家移动	*
void PlayerMove(char arr[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("请输入要下棋的坐标:\n");
	//getchar();
	while (1)
	{
		scanf("%d %d", &x, &y);
		if ((((x - 1) >= 0) && ((x - 1) < ROW)) && (((y - 1) >= 0 )&& ((y - 1) < COL)))
		{
			if (arr[x-1][y-1] == ' ')
			{
				arr[x-1][y-1] = '*';
				break;
			}
			else
			{
				printf("坐标已被占用,请重新输入坐标\n");
			}
		}
		else
		{
			printf("输入坐标超出范围,请重新输入:\n");
		}
	}
}

        如上述代码所示,我们用while(1)来实现死循环,直到玩家输入了正确的、没被占用的坐标内容,才能跳出这个循环。接着,玩家走完了应该新打印一个棋盘,来显示玩家到底下在哪里。

        然后再进行电脑下棋。由于电脑下棋不用判断是否会下棋盘外的棋子,所以比起玩家,只需要在棋盘内进行随机下就行。因为是随机,所以我们就要用到rand了。

        在ComputerMove函数内部打上x = rand()% row; y = rand()% col;模上长和宽,最后输出的值就只有比长宽更小的数字了。比如:当row和col为3时,任何数%3,那都只剩下0/1/2,就刚好是二维数组的坐标,在ComputerMove中引用了rand后,要在text.c文件中的text函数的do while语句执行前加上srand((unsigned int)time(NULL));让这个伪随机值rand,随着时间变化而变化,实现真随机(注意上面这具代码不能加入循环语句中,我们只要取一次时间,那后续的数字都是随机的)因为用了rand和srand还有time,我们要在game.h文件中,加两个头文件#include<stdlib.h>#include<time.h>

        接着在电脑走完之后,我们也要重新打印棋盘,来看看电脑走了哪步。所以在game函数中的ComputerMove(arr, ROW, COL);后面加一个PrintArr(Arr, ROW, COL);电脑下棋代码如下:

        ComputerMove()电脑移动函数
//电脑移动
void ComputerMove(char arr[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	while (1)
	{
		x = rand() % ROW;//控制在0、1、2
		y = rand() % COL;	
		if (arr[x][y] == ' ')
		{
			arr[x][y] = '#';
			break;
		}
	}
}

        当我们实现了玩家和电脑一步一步的下棋,最后就要实现游戏胜利的条件了。先在game函数中定义一个char类型的变量ret用于接收不同情况下的返回值。写一个IsWin()函数,放在game.c文件中,用于检测游戏当前状态,条件为:若电脑胜利,返回#。若玩家胜利,返回*。若平局(棋盘被下满了),返回p。若没有结束游戏,且没有平局,则继续,返回j。

        具体代步骤为:先判断横竖,返回值就是三个相等的字符的其中一个字符(因为电脑是输入#,玩家是输入*,返回的值可以直接用于判断哪方获胜)接着判断两个斜着的,同理也是直接返回数组里面的字符。

        然后,我们要判断平局,平局的条件为:棋盘满了,且没有一方获胜,所以我们要再创建一个函数IsFull(),来判断棋盘是否满了。满了IsFull()函数返回1给IsWin()函数,然后IsWin函数再返回P。若三者都没达成条件,则返回j,表示游戏继续。IsWin()代码如下:

        IsWin()判断当前状况函数
//判断胜利
//玩家胜利,返回*
//电脑胜利,返回#
//继续,返回j
//平局,返回p
char IsWin(char arr[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	//判断横
	for (x = 0; x < ROW; x++)
	{
		int PlayerWin = 0;
		int ComputerWin = 0;
		for (y = 0; y < COL; y++)
		{
			if (arr[x][y] == '*')
			{
				PlayerWin++;
			}
			if (arr[x][y] == '#')
			{
				ComputerWin++;
			}
		}
		if (ComputerWin == ROW)
		{
			return '#';
		}
		if (PlayerWin == ROW)
		{
			return '*';
		}

	}

	//判断竖
	for (y = 0; y < COL; y++)
	{
		int PlayerWin = 0;
		int ComputerWin = 0;
		for (x = 0; x < ROW; x++)
		{
			if (arr[x][y] == '*')
			{
				PlayerWin++;
			}
			if (arr[x][y] == '#')
			{
				ComputerWin++;
			}
		}
		if (PlayerWin == COL)
		{
			return '*';
		}
		if (ComputerWin == COL)
		{
			return '#';
		}
	}

	//判断交叉
	int PlayerWin = 0;
	int ComputerWin = 0;
	for (x = 0, y = 0; (x < ROW) && (y < COL); x++, y++)
	{
		if (arr[x][y] == '*')
		{
			PlayerWin++;
		}
		if (arr[x][y] == '#')
		{
			ComputerWin++;
		}
		if (PlayerWin == COL)
		{
			return '*';
		}
		if (ComputerWin == COL)
		{
			return '#';
		}
	}
	PlayerWin = 0;
	ComputerWin = 0;
	for (x = ROW-1, y = 0; (x > 0) && (y < COL); x--, y++)
	{
		if (arr[x][y] == '*')
		{
			PlayerWin++;
		}
		if (arr[x][y] == '#')
		{
			ComputerWin++;
		}
		if (PlayerWin == COL)
		{
			return '*';
		}
		if (ComputerWin == COL)
		{
			return '#';
		}
	}
	//判断是否填满了
	if (IsFull(arr, ROW, COL))
	{
		return 'p';
	}
	//以上都不满足时,则游戏继续,返回j
	return 'j';
}

由于判断横竖有很多相同的地方,这样会导致代码很长。在输赢判断完之后再检测一下是否填满了,把IsFull()函数放在IsWin()函数上面。IsFull()函数代码如下:

        IsFull()判断是否填满函数
int IsFull(char arr[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	for (x = 0; x < ROW; x++)
	{
		for (y = 0; y < COL; y++)
		{
			if (arr[x][y] == ' ')
				return 0;
		}
	}
	return 1;
}

        我们接着看回game.c文件中的部分代码。整个game函数里为了实现游戏进行而创建的一个一个嵌套函数,若IsWin返回的值不是j,即游戏结束,break跳出死循环,然后下面再用if判断返回的是哪个字符,从而打印谁获胜或者平局。

	char ret = 'j';//判断游戏是否继续的条件
	while (1)
	{
		PlayerMove(arr, ROW, COL);
		PrintArr(arr, ROW, COL);
		ret = IsWin(arr, ROW, COL);
		if (ret != 'j')
		{
			break;
		}
		ComputerMove(arr, ROW, COL);
		PrintArr(arr, ROW, COL);
		ret=IsWin(arr, ROW, COL);
		if (ret != 'j')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家胜利\n");
	}
	if (ret == '#')
	{
		printf("电脑胜利\n");
	}
	if (ret == 'p')
	{
		printf("平局\n");
	}
}

        判断完胜利后,全部代码已经写完,功能也就实现了,就可以进行测试游玩了。最后我们来看一下全部的代码。

        全部代码

        text.c

//三子棋小游戏
#include"game_3ziqi.h"
//菜单
void mune()
{
	printf("*************************\n");
	printf("*******  1.play  ********\n");
	printf("*******  0.exit  ********\n");
	printf("*************************\n");
}
void game()
{
	char arr[ROW][COL] = {0};
	ChuShi(arr, ROW, COL);
	PrintArr(arr, ROW, COL);
	char ret = 'j';//判断游戏是否继续的条件
	while (1)
	{
		PlayerMove(arr, ROW, COL);
		PrintArr(arr, ROW, COL);
		ret = IsWin(arr, ROW, COL);
		if (ret != 'j')
		{
			break;
		}
		ComputerMove(arr, ROW, COL);
		PrintArr(arr, ROW, COL);
		ret=IsWin(arr, ROW, COL);
		if (ret != 'j')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家胜利\n");
	}
	if (ret == '#')
	{
		printf("电脑胜利\n");
	}
	if (ret == 'p')
	{
		printf("平局\n");
	}
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		mune();
		printf("是否游玩(0/1)?\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
		default:
			printf("输入错误,请重新输入!\n");
		}
	} while (input);
	return 0;
}

        game.c

#include"game_3ziqi.h"

//初始化数组
void ChuShi(char arr[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < ROW; i++)
	{
		int j = 0;
		for (j = 0; j < COL; j++)
		{
			//把二维数组全部放空格清零
			arr[i][j] = ' ';
		}
	}
}

//打印棋盘
//   |   |   
//---|---|---
//   |   |   
//---|---|---
//   |   |   
void PrintArr(char arr[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 ",arr[i][j]);
			if (j < COL - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		//打印分割行
		for (j = 0; j < COL; j++)
		{
			//分割行只打印2列
			if (i < ROW - 1)
			{
				printf("---");
				if (j < COL - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

//玩家移动	*
void PlayerMove(char arr[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("请输入要下棋的坐标:\n");
	//getchar();
	while (1)
	{
		scanf("%d %d", &x, &y);
		if ((((x - 1) >= 0) && ((x - 1) < ROW)) && (((y - 1) >= 0 )&& ((y - 1) < COL)))
		{
			if (arr[x-1][y-1] == ' ')
			{
				arr[x-1][y-1] = '*';
				break;
			}
			else
			{
				printf("坐标已被占用,请重新输入坐标\n");
			}
		}
		else
		{
			printf("输入坐标超出范围,请重新输入:\n");
		}
	}
}

//电脑移动
void ComputerMove(char arr[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	while (1)
	{
		x = rand() % ROW;//控制在0、1、2
		y = rand() % COL;	
		if (arr[x][y] == ' ')
		{
			arr[x][y] = '#';
			break;
		}
	}
}

//判断胜利
//玩家胜利,返回*
//电脑胜利,返回#
//继续,返回j
//平局,返回p
int IsFull(char arr[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	for (x = 0; x < ROW; x++)
	{
		for (y = 0; y < COL; y++)
		{
			if (arr[x][y] == ' ')
				return 0;
		}
	}
	return 1;
}
char IsWin(char arr[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	//判断横
	for (x = 0; x < ROW; x++)
	{
		int PlayerWin = 0;
		int ComputerWin = 0;
		for (y = 0; y < COL; y++)
		{
			if (arr[x][y] == '*')
			{
				PlayerWin++;
			}
			if (arr[x][y] == '#')
			{
				ComputerWin++;
			}
		}
		if (ComputerWin == ROW)
		{
			return '#';
		}
		if (PlayerWin == ROW)
		{
			return '*';
		}

	}

	//判断竖
	for (y = 0; y < COL; y++)
	{
		int PlayerWin = 0;
		int ComputerWin = 0;
		for (x = 0; x < ROW; x++)
		{
			if (arr[x][y] == '*')
			{
				PlayerWin++;
			}
			if (arr[x][y] == '#')
			{
				ComputerWin++;
			}
		}
		if (PlayerWin == COL)
		{
			return '*';
		}
		if (ComputerWin == COL)
		{
			return '#';
		}
	}

	//判断交叉
	int PlayerWin = 0;
	int ComputerWin = 0;
	for (x = 0, y = 0; (x < ROW) && (y < COL); x++, y++)
	{
		if (arr[x][y] == '*')
		{
			PlayerWin++;
		}
		if (arr[x][y] == '#')
		{
			ComputerWin++;
		}
		if (PlayerWin == COL)
		{
			return '*';
		}
		if (ComputerWin == COL)
		{
			return '#';
		}
	}
	PlayerWin = 0;
	ComputerWin = 0;
	for (x = ROW-1, y = 0; (x > 0) && (y < COL); x--, y++)
	{
		if (arr[x][y] == '*')
		{
			PlayerWin++;
		}
		if (arr[x][y] == '#')
		{
			ComputerWin++;
		}
		if (PlayerWin == COL)
		{
			return '*';
		}
		if (ComputerWin == COL)
		{
			return '#';
		}
	}
	//判断是否填满了
	if (IsFull(arr, ROW, COL))
	{
		return 'p';
	}
	//以上都不满足时,则游戏继续,返回j
	return 'j';
}

        game.h

#include<stdio.h>//printf
#include<time.h>//time
#include<stdlib.h>//rand,srand

#define ROW 3
#define COL 3

//函数声明
//初始化棋盘
void ChuShi(char arr[ROW][COL], int row, int col);
//打印棋盘
void PrintArr(char arr[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char arr[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char arr[ROW][COL], int row, int col);
//判断胜利
char IsWin(char arr[ROW][COL], int row, int col);

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值