c语言 三子棋详细解析 (零基础也能看懂)附源码 c语言小游戏

代码运行结果如下
在这里插入图片描述

代码实现

test.c(测试游戏的逻辑)
game.h(关于游戏相关的函数声明符号声明)头文件包含的

game.c游戏相关函数的实现

test.c

游戏如何玩
希望游戏玩完一把还可以继续玩
/
*
用dowhile形式 (无论如何都会进去一次 打印一个菜单)

打印菜单
void menu()
{

	printf("***************************\n");
	printf("*********  1.play   ********\n");
	printf("*********  0.exit   *******\n");
	printf("***************************\n");


}
int main()/*希望游戏玩完一把还可以继续玩*/
{
	do
	{
		menu();
	} while ();

	return 0;
}
//上面代码的意思就是按下运行后会在屏幕上打印一个菜单 菜单的内容就是printf的里  像一个图案。

打印完字符 给用户一个反馈 让用户知道要干嘛 然后用户要选择 1 还是2 所以用scanf接收

int main()/*希望游戏玩完一把还可以继续玩*/
{
	do
	{
		int input = 0;
		menu();
		printf("请选择");
			scanf("%d",&input)//比如用户选择1 输入了1这个scanf就起到了接受的作用,input就是把选择的值存起来
	} while ();

	return 0;
}


然后根据他选的值作出反应 下面代码如下

int main()/*希望游戏玩完一把还可以继续玩*/
{
	int input = 0;
	do
	{
		
		menu();
		printf("请选择");
		scanf("%d", &input);
			switch (input)
			{
			case 1://选择1做出的反应
				printf("三子棋游戏\n");
				    break;
			case 0:
				printf("退出游戏\n");

					break;
				default://如果选择的不是0也不是1,会跑到这里
					printf("输入错误,重新选择\n");
					break;
			}//break 跳出的是switch语句会来到这里 执行下面的
	} while (input);//不管做了哪种选择最后这里进行判断放入input。解析为啥input 因为如果选择1 玩完后break跳出来 下面while(1)又执行一遍 我们的玩完还想玩目的就达到了。直到选择0while(0)为假跳出来


	return 0;
}

在这里插入图片描述
default作用如下
在这里插入图片描述
**解析为啥input 因为如果选择1 玩完后break跳出来 下面while(1)又执行一遍 我们的玩完还想玩目的就达到了。直到选择0while(0)为假跳出来
**


完成了初步接下来我们就可以来进入三子棋了 用到game函数 放到case1下 调用下函数, 函数实现还得main在上面
voidgame 不需要返回 里边只要是三子棋运行逻辑就行三子棋都在这里完成
game函数实现分析如下
根据我们的运行结果可以得出如下
在这里插入图片描述
一个字也没下的时候是这样的
**
在这里插入图片描述
1.玩家下一个电脑下一个 发现玩家下完电脑下的时候 玩家的旗子还在 还有记录 电脑玩家同理
2.下完之后要记录 由图可以看出我们这是一个3×3的格子,所以我们可以用一个3×3的二维数组来记录
** 3.没有落子的时候是空的所以是空格 玩家落子给*号电脑落子给#号

#define  _CRT_SECURE_NO_WARNINGS  1
#include <stdio.h>//游戏如何玩
void game()
{
	//游戏的运行需要存储数据  所以用到了二维数组 二维数组的创建用到了char因为游戏的实现用到的都是字符 *#类似的
	char board[3][3]//board是自己定义的 我用了board是为了更容易理解
	**3×3可能不够 用了就得改比较麻烦 关于棋盘大小是游戏的一些属性了所以咱们直接写到game.h里**
}
void menu()
{

	printf("***************************\n");
	printf("*********  1.play   ********\n");
	printf("*********  0.exit  *******\n");
	printf("***************************\n");


}
int main()/*希望游戏玩完一把还可以继续玩*/
{
	int input = 0;
	do
	{
		
		menu();
		printf("请选择");
		scanf("%d", &input);
			switch (input)
			{
			case 1://选择1做出的反应
				game();//把之前的删了是因为之前放那个更好理解 
				    break;

			case 0:
				printf("退出游戏\n");

					break;
				default://如果选择的不是0也不是1,会跑到这里
					printf("输入错误,重新选择\n");
					break;
			}//break 跳出的是switch语句会来到这里 执行下面的
	} while (input);//不管做了哪种选择最后这里进行判断放入input. 解析为啥input 因为如果选择1 玩完后break跳出来 下面while(1)又执行一遍 我们的玩完还想玩目的就达到了。直到选择0while(0)为假跳出来

	return 0;
}

game.h (头文件新建)

在这里插入图片描述
游戏的头文件有了 还需要一个游戏的实现 game.c
在这里插入图片描述

game.h下放这两个

#pragma once
#define ROW 3//define 定义符号  这两个符号是行和列的意思
#define COL 3

因为刚刚的头文件 然后我们这里可以直接引用 如果要做修改可以在我们创建的game.h里修改 这样写的好处有利于后续的更改 比如想玩5子棋直接改头文件ROW LOC就行就不需要动用其他的 。头文件还有一个好处就是只要谁想用都可以直接调用
在这里插入图片描述
报错是因为没有引用 如下
在这里插入图片描述


有我们的最终结果运行图可以看出来用到了很多的空格
所以我们先打印一个全都是空格的

直接放到函数里实现 定义initboard()如下:

void game()
{
	//游戏的运行需要存储数据  所以用到了二维数组 二维数组的创建用到了char因为游戏的实现用到的都是字符 *#类似的
	char board[ROW][COL];//board是自己定义的 我用了board是为了更容易理解
	InitBoard(board,ROW,COL);//因为这个函数要初始化上面的棋盘 所以传过去 二维数组。
	//因为不知道几行几列所以rowcol一块传过去. 这个初始化棋盘 属于游戏模块 放到game.h中实现
}

#pragma once
//符号的定义
#define ROW 3//define 定义符号  这两个符号是行和列的意思
#define COL 3


//函数的声明
//InitBoard(board, ROW, COL)  这个单独拿过来做对比 因为之前传三个 ,声明的时候也需要三个
//下面是初始化棋盘函数
void InitBoard(char board[ROW][COL], int row, int col);//第一个数组 交代数组行和列。 第二三个行和列 接收真实传递给他的行和列
//上面函数写完了要实现 去game.c里实现

接下来在game.h中实现给数组的每个元素初始化成空格 代码如下:

初始化棋盘函数
void InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)//row是行
	{
		for (j = 0; j < col; j++)
		{
			//原理 如果他们真的传过来3 3 这里是访问三行三列的元素 每个元素都会被初始化为空格
			board[i][j] = ' ';//
		}
	}

}

打印棋盘(displayboard)

打印棋盘本质上是打印数组内容
因为打印数组所以要把数组内容传过去
在这里插入图片描述打印棋盘就出现,然后去game.h中声明
在这里插入图片描述
打印完也需要实现 区game.c中实现

函数是放在头文件定义 而在函数里边进行相应的实现


在这里插入图片描述

打印这样一个棋盘
在这里插入图片描述
紫色圈起来的 打印方法—|—|—
红色也就是第一个方法空格%c一个空格。一个字符一个空格然后| 大概原理就是这样 ,一行数据一行分割看成一组
实现如下

void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
		printf("---|---|---\n");

	}


}

运行一下 发现不行因为没有引用头文件 stdio 咱们直接在头文件中引用就可以了
在这里插入图片描述
————————————————————————
打印下看看目前进度
在这里插入图片描述
发现多了一行 接下来演示控制代码不打印最后一行
在这里插入图片描述


在这里插入图片描述

打印中如果遇见这种情况 是因为你没有初始化棋盘格(初始化空格)
void InitBoard(char board[ROW][COL],int row, int col);


如果我们需一个不是3行3列的棋盘格如下
在这里插入图片描述
显然这样打印出来不太合适,所以需要改造下代码让他通用起来
在这里插入图片描述
把每一行数据加一个竖杠作为一个
在这里插入图片描述
分割行如何处理如下
printf(“—|—|—\n”)这一行拆开

if (i < row - 1)
			/*printf("---|---|---\n");*///这一行的打印不是总打印 可以给个判断
		{
			int j = 0;
			for (j = 0; j < col; j++)
			{
				printf("---");
				if(j<col-1)
				printf("|");//这个再打印的时候不是同时打印的 所以加上循环
			}
			printf("\n");//从j=0这一行打印完换行
		}

在这里插入图片描述
这样就解决了游戏局限于3×3的


在这里插入图片描述
在这里插入图片描述
接下来放到game.c里实现如下

在这里插入图片描述
玩家输入11的时候其实代表数组为00
在这里插入图片描述
发现打印之后不能看到 解决如下
把打印的代码在主函数内部复制下就可以
在这里插入图片描述
在这里插入图片描述

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)//对于玩家来说行列从1开始 所以这样写
		{
			//下棋  首先判断坐标有没有被占用.判断的方法就是没有被占用的时候里面是空格
			if (board[x - 1][y - 1] == ' ')//玩家输入11的时候其实代表数组为00  所以xy减去1
			{
				board[x - 1][y - 1] = '*';//玩家下棋放一颗星号  这时候玩家下棋了 所以break跳出
				break;
			}
			else
			{
				printf("坐标被占用,请重新输入\n");//如果已经不是空格了
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
		}
	}
}

电脑下棋

在这里插入图片描述

game.h 实现

在这里插入图片描述

game.c

电脑怎么下棋 让他随机下
**里边用到了rand随机数函数 rand在生成坐标前要调用 srand 因为他在整个代码里只需要执行一次所以放到main函数里 因为main函数只会执行一次 **

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑走:>\n");
	//电脑怎么 走 第一步生成坐标
	int x = rand();
	int y = rand();

}
srand((unsigned int)time(NULL));//用time函数返回值作为随机数的生成器  time函数调用的时候传一个空指针。返回类型强制转换为
	

在这里插入图片描述
srand和time函数需要头文件 引用到 game.h就可以在这里插入图片描述
接下来就可以设置随机数了

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑走:>\n");
	//电脑怎么 走 第一步生成坐标
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;//模上谁得到谁
		//判断落子
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}

	}
}

在这里插入图片描述
没有输赢是不完整的如下
在这里插入图片描述
四种状态
IsWin 用来判断游戏的状态
在这里插入图片描述
代码实现
判断输赢还是的看数组里边有没有三个相连的,所以其实还是要传参过去
在这里插入图片描述


在这里插入图片描述

以下图一可以写成图二
在这里插入图片描述
在这里插入图片描述
接下来写 iswin
在这里插入图片描述
接下来在game.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][1] != ' ')
		{
			return board[i][1];

		}
	}
	//判断三列
	for (i = 0; i < col; i++)\
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[1][i];
		}

	}
}

在这里插入图片描述

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][1] != ' ')
		{
			return board[i][1];

		}
	}
	//判断三列
	for (i = 0; i < col; i++)\
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[1][i];
		}

	}
	//判断对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	//判断平局(判断棋盘是否满了)满没满就看有没有空格了一个空格也没了那他就满了
	int ret =IsFull(board, row, col);//如果棋盘满了返回一 不满返回0 平局返回q
	if (ret == 1)
	{

		return 'Q';
	}
	//如果都没有  那就继续继续返回C
	return 'C';
}

接下在这个函数上边实现isfull函数

int IsFull(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;//棋盘没满
			}

		}
	}
	return 1;//棋盘满了
}

在这里插入图片描述
游戏完成

如果有人需要完整版源码联系我我会发出来

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值