[c语言日寄]精英怪:三子棋(tic-tac-toe)3命慢通[附免费源码]

哈喽盆友们,今天带来《c语言》游戏中[三子棋boss]速通教程!我们的目标是一边编写博文,一边快速用c语言实现三子棋游戏。准备好瓜子,我们计时开始!

前期规划

在速通中,我们必须要有清晰的前期规划,我选用了一下框架

c 复制代码
int main() {

	//棋盘
	return 0;
}
//初始UI
//游玩显示模块
//用户操作模块
//胜利判定模块
//结算界面

初始UI

初始UI是最为简单的部分之一,我们可以在此快速输出,为接下来的算法腾出时间。

我们使用printf函数直接实现可视化UI,然后使用scanf读取用户的操作。

c 复制代码
	int num = 0;
	printf("-----------------------\n");
	printf("  欢迎来到三子棋游戏!\n");
	printf("   # 1.开始游戏\n");
	printf("   # 2.退出游戏\n");
	printf("-----------------------\n");
	printf("请输入操作序号:");
	scanf_s("%d", &num);

使用switch函数进行分流,并且添加上一个简单的输入检测:

c 复制代码
	again:
	int num = 0;
	printf("-----------------------\n");
	printf("  欢迎来到三子棋游戏!\n");
	printf("   # 1.开始游戏\n");
	printf("   # 2.退出游戏\n");
	printf("-----------------------\n");
	printf("请输入操作序号:");
	scanf_s("%d", &num);
	switch (num) {
	case 1:return 1;
	case 2:return -1;
	default:
		system("cls");
		printf("#无效的操作符输入\n");
		goto again;//通过goto实现快速构建循环。
	}

配合return,函数的声明为:int UI();

在主函数中通过if语句引用UI,并且实现退出选项。

UI函数到此为止。完整代码如下:

c 复制代码
#include<stdio.h>
#include<windows.h>

int UI();

int main() {
	
	//展示UI
	if (UI() == -1)return 0;
	//棋盘
	return 0;
}

//初始UI

int UI() {

	again:
	int num = 0;
	printf("-----------------------\n");
	printf("  欢迎来到三子棋游戏!\n");
	printf("   # 1.开始游戏\n");
	printf("   # 2.退出游戏\n");
	printf("-----------------------\n");
	printf("请输入操作序号:");
	scanf_s("%d", &num);
	switch (num) {
	case 1:return 1;
	case 2:return -1;
	default:
		system("cls");
		printf("#无效的操作符输入\n");
		goto again;
	}

}
//游玩显示模块
//用户操作模块
//胜利判定模块
//结算界面

具体的效果如下:

此时的时间为:

棋盘

清理了小兵之后,boss战才开始打响:

我们需要构建三子棋的棋盘。

为了方便判定,我将33的棋盘嵌入55的数组中。

c 复制代码
	//棋盘
	int chess[5][5];
	memset(chess, 0, sizeof(int) * 25);//棋盘初始化

通过string.h头文件中memset函数,我们完成了对棋盘的初始化。

游玩显示模块

此时,boss血条已经下降了四分之一,boss进入红温阶段。

我们需要建立一个函数输出游玩时的界面。

这是一个双人游戏,所以棋盘有3种状态:空白,X棋子,O棋子。

我用0代表空格,用1代表X棋子,用2代表O棋子。

建立print_under函数实现对单个格子的可视化:

c 复制代码
void print_under(int*arr ,int i, int j) {

	if (*(arr + i * 3 + j) == 0)printf("·\t");
	else if (*(arr + i * 3 + j) == 1)printf("X\t");
	else if (*(arr + i * 3 + j) == 2)printf("O\t");
	else printf("Error\t");
	return;
}

通过vision函数实现棋盘整体的输出:

c 复制代码
//游玩显示模块
void vision(int* arr) {

	system("cls");

	printf("-----------------------\n");
	for (int i = 1; i < 4; i++) {
		for (int j = 1; j < 4; j++) {
			print_under(arr,i, j);
		}
		printf("\n");
	}
	printf("-----------------------");

}

效果如下

不过,我在此时发现一个bug,就是在UI()函数中,goto语句将变量定义包涵进去了,这样会导致变量的重定义,这吓了我一身冷汗,急忙改了回来:

c 复制代码
//原式
int UI() {
	again:
	int num = 0;//原来的定义放在again标签前
	printf("-----------------------\n");
c 复制代码
//改后
int UI() {
	int num = 0;//转移到标签外面
	again:
	printf("-----------------------\n");

很好,此时我们成功完成了这个模块。

用时:

用户操作模块

boss血量剩下50%,boss进入第二阶段!!boss放大招了!我们必须挺过这里!

建立op()函数,引入user变量实现玩家1和玩家2的区分。

用scanf读取用户操作,并且设立输入检查:

c 复制代码
void op(int* arr, int user) {
	int i, j;
	again1:
	if (user % 2 == 0) {
		printf("玩家1:请输入落子位置");
		scanf_s("%d%d", &i, &j);
		if (i < 4 && i > 0)
			if (j < 4 && j > 0)
				if (*(arr + 3 * i + j) == 0)
					*(arr + 3 * i + j) = 1;
				else { printf("#无效的操作:你似乎下在了已经有棋子的地方哦\n");goto again1; }
			else { printf("#无效的操作:你似乎下到了界外诶\n");goto again1; }
		else { printf("#无效的操作:你似乎下到了界外诶\n");goto again1; }

	}
	if (user % 2 == 1) {
		printf("玩家2:请输入落子位置");
		scanf_s("%d%d", &i, &j);
		if (i < 4 && i > 0)
			if (j < 4 && j > 0)
				if (*(arr + 3 * i + j) == 0)
					*(arr + 3 * i + j) = 2;
				else { printf("#无效的操作:你似乎下在了已经有棋子的地方哦\n");goto again1; }
			else {printf("#无效的操作:你似乎下到了界外诶\n");goto again1; }
		else { printf("#无效的操作:你似乎下到了界外诶\n");goto again1; }
	}

}

此时,我还对游玩显示模块进行了优化

c 复制代码
void vision(int* arr) {

	system("cls");

	printf("----------------------------\n");
	printf("\t1\t2\t3\n");
	for (int i = 1; i < 4; i++) {
		printf("%d\t", i);
		for (int j = 1; j < 4; j++) {
			print_under(arr,i, j);
		}
		printf("\n");
	}
	printf("----------------------------\n");

}

此时的效果:

此时,我一共花费了以下时间:(显示问题:真实的时间为图示的时间加上1个小时)

胜利判定

此时boss血量见底,让我们来一段漂亮的斩杀把!

完成胜利判定模块:

c 复制代码
// 胜利判定模块
int victory(int* arr, int user) {
	int player = (user % 2 == 0) ? 1 : 2;

	// 横向判定
	for (int i = 1; i < 4; i++) {
		if (*(arr + i * 3 + 1) == player && *(arr + i * 3 + 2) == player && *(arr + i * 3 + 3) == player) {
			return player;
		}
	}

	// 纵向判定
	for (int j = 1; j < 4; j++) {
		if (*(arr + 1 * 3 + j) == player && *(arr + 2 * 3 + j) == player && *(arr + 3 * 3 + j) == player) {
			return player;
		}
	}

	// 左斜线判定
	if (*(arr + 1 * 3 + 1) == player && *(arr + 2 * 3 + 2) == player && *(arr + 3 * 3 + 3) == player) {
		return player;
	}

	// 右侧斜线判定
	if (*(arr + 1 * 3 + 3) == player && *(arr + 2 * 3 + 2) == player && *(arr + 3 * 3 + 1) == player) {
		return player;
	}

	return 0;
}

经历了痛苦的改bug,

我终于意识到,原来数组只要3*3就好了TAT,于是我默默的把标题的1命速通改为3命速通(悲)。

那么用时多久呢?

没错,两个半小时!(计时器忽略了小时计数)

一位破防的靓仔把标题的1命速通改为3命慢通......

嘿嘿

虽然速通失败,但是博主其实很有实力的!

关注博主,总有一天我会证明给你看(OvO)~

相关推荐
Blasit43 分钟前
Qt C++ QStatusbar 显示表示状态的图片
开发语言·c++·qt
木心操作1 小时前
js使用qrcode与canvas生成带logo的二维码
开发语言·javascript·ecmascript
SunkingYang1 小时前
C/C++中,const、static关键字有什么作用,如何定义、初始化,什么情形下需要用到这两关键字?
c语言·c++·const·static·初始化·申明·定义
利刃大大3 小时前
【C语言】内存函数详解与模拟实现
c语言·开发语言
疯狂的沙粒3 小时前
如何将一个数组转换为字符串?
开发语言·前端·javascript·柔性数组
shix .3 小时前
python范围
开发语言·python
网络安全queen4 小时前
Web 学习笔记 - 网络安全
前端·笔记·学习
源之缘-OFD先行者4 小时前
FreeType 介绍及 C# 示例
开发语言·c#
惊鸿一梦q4 小时前
qt5Core.dll是什么文件,qt5Core.dll错误怎么办
开发语言·qt