自学内容网 自学内容网

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

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

前期规划

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

int main() {

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

初始UI

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

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

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

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函数到此为止。完整代码如下:

#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的数组中。

//棋盘
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函数实现对单个格子的可视化:

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函数实现棋盘整体的输出:

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

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

很好,此时我们成功完成了这个模块。
用时:
在这里插入图片描述

用户操作模块

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

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

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; }
}

}

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

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血量见底,让我们来一段漂亮的斩杀把!
完成胜利判定模块:


// 胜利判定模块
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)~


原文地址:https://blog.csdn.net/2401_83741734/article/details/145082406

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!