前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >[c语言日寄]精英怪:三子棋(tic-tac-toe)3命慢通[附免费源码]

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

作者头像
siy2333
发布2025-02-05 12:48:01
发布2025-02-05 12:48:01
7400
代码可运行
举报
文章被收录于专栏:来自csdn的博客来自csdn的博客
运行总次数:0
代码可运行

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

前期规划

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

代码语言:javascript
代码运行次数:0
复制
int main() {

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

初始UI

初始UI是最为简单的部分之一,我们可以在此快速输出,为接下来的算法腾出时间。 我们使用printf函数直接实现可视化UI,然后使用scanf读取用户的操作。

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

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

代码语言:javascript
代码运行次数:0
复制
	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函数到此为止。完整代码如下:

代码语言:javascript
代码运行次数:0
复制
#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的数组中。

代码语言:javascript
代码运行次数:0
复制
	//棋盘
	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函数实现对单个格子的可视化:

代码语言:javascript
代码运行次数:0
复制
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函数实现棋盘整体的输出:

代码语言:javascript
代码运行次数:0
复制
//游玩显示模块
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语句将变量定义包涵进去了,这样会导致变量的重定义,这吓了我一身冷汗,急忙改了回来:

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

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

用户操作模块

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

建立op()函数,引入user变量实现玩家1和玩家2的区分。 用scanf读取用户操作,并且设立输入检查:

代码语言:javascript
代码运行次数:0
复制
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; }
	}

}

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

代码语言:javascript
代码运行次数:0
复制
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血量见底,让我们来一段漂亮的斩杀把! 完成胜利判定模块:

代码语言:javascript
代码运行次数:0
复制
// 胜利判定模块
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)~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前期规划
  • 初始UI
  • 棋盘
  • 游玩显示模块
  • 用户操作模块
  • 胜利判定
  • 嘿嘿
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档