目录
前言:
在前面的九课中,我们学习了C语言程序的各个重要组成部分,结合往期文末的一些练习,想必现在大家对于知识已经有了不错的掌握,本文我将带领各位小伙伴们运用我们之前学过的知识,使用标准工程格式来写出我们的第一个小游戏——井字棋(又名三子棋)。
一、文件建立:
按照我们之前提到过的标准工程格式,我们首先建立三个文件:
1.头文件game.h:
该文件用于包含其它头文件,并存放功能实现函数的函数声明。好处是可以整合整个程序中所用到的全部头文件和函数声明,一目了然。并在引用时只需引用头文件game.h,其它被包含的头文件与函数声明均生效,省时省力:
2.函数定义文件game.c:
该文件用于书写所有的程序功能实现的函数定义。使用这样格式的好处主要有三点:一来将所有定义书写在一起,便于我们进行阅读和修改;二是大大提升了程序的可移植性,当他人想要使用我们定义的函数时,只需将整个game.c文件发送给对方即可;第三点也是最重要的一点,我们可以通过将其设置为静态库,使其被转化为二进制码而进行加密,从而对我们的核心函数实现进行隐藏:
3.工程测试文件test.c:
该文件用于书写我们的程序主体部分,供我们通过使用代码来对程序进行执行逻辑的编辑和检查。结合前两个文件的使用,可以使得我们的程序逻辑变得清晰,极有利于我们进行程序的运行逻辑检查:
二、编写井字棋游戏:
1.程序整体执行思路:
各位小伙伴们一定都玩过各种各样的游戏,对于游戏也都有一定的了解。而游戏最中心的程序主体也不过是界面和游戏实现两个部分,依此我们可以直接写出井字棋小游戏的最核心主体:
void menu(void)
//菜单函数
{
...
}
void game(void)
//游戏函数
{
...
}
void test()
//整体流程
{
menu();
game();
...
}
int main()
{
test();
return 0;
}
他的执行流程很明确:自定义两个函数,menu为菜单函数,负责向玩家打印游戏菜单;game为游戏函数,负责实现整个游戏的逻辑实现。当程序开始编译运行后,将会按照顺序,先执行menu函数打印出游戏菜单,接着执行game函数让玩家们进行游戏。
并且我们都知道,大多数时候玩家往往会选择多次进行游戏,所以我们通过在数函数部分结合我们在之前介绍过的的循环和分支语句很容易实现该目的:
void test()
{
int input = 0;
do
{
menu();
printf("请您进行选择:");
scanf("%d", input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while (input);
return 0;
}
通过使用do...while循环语句,既可以保证我们的玩家选择判断至少被执行一次,又可以供玩家选择继续游戏。
又通过使用switch分支语句,在打印出游戏菜单后让玩家进行选择,若玩家选择1则继续进行游戏,选择0则退出游戏。同时对输入数据进行合法性检测,使输入数据既不是1也不是0时要求玩家重新进行输入。
我们将程序运行起来检查一下我们的程序主体逻辑功能:
可以看到整个循环与分支选择以及功能模块都已成功实现,至此程序主体部分就已经确定好了,接下来只需完成功能模块的逻辑实现即可。
2.menu菜单函数实现:
确定了程序的主体逻辑结构,我们就开始着手进行具体功能的实现。首当其冲的便是向玩家们展示游戏内容的menu菜单函数。
实质上这一部分并没有什么难度,这部分的功能仅仅是向玩家们打印出游戏功能供玩家们阅读,并没有实质的逻辑处理,因此仅使用printf函数即可轻松实现:
void menu()
{
printf("************************\n");
printf("************************\n");
printf("**** 欢迎游玩三子棋 ****\n");
printf("**** 请选择 ****\n");
printf("**** 1.开始游戏 ****\n");
printf("**** 0.退出游戏 ****\n");
printf("************************\n");
printf("************************\n");
}
没错,菜单函数就是这么朴实无华,运行起来看看效果:
轻轻松松,对于现在的小伙伴们来说正能说是是小菜一碟。菜单功能已经实现,可以进行到下一模块的编写。
3.game游戏函数逻辑:
(注:此处我们只关心实现逻辑,而具体功能实现后面会逐一进行研究)
程序的主体确定好了,游戏菜单也成功打印出来了,但是我们都很清楚,三子棋最重要的,还是游戏内容的实现,毕竟没有玩家会愿意去玩一个仅仅只有菜单的“游戏”。
首先我们要来了解一下三子棋游戏的游戏规则和胜利条件,只有了解了这些我们才能进行相关功能的实现。三子棋顾名思义,首先它是一种棋类游戏,它有标准的3×3九宫格棋盘,由游戏双方交替着棋,两方相互进行阻拦,当其中一方达成同一排、同一列或斜向三颗棋子连线时,该玩家获得胜利。
梳理了规则,我们开始尝试实现。
在游戏函数中,首先我们进行棋盘的初始化,即在game函数内打印出内留着棋位置的九宫格棋盘。具体的实现方式是,创建一个九宫格数组,用于处理玩家与电脑的着棋操作,同时在没有着棋的位置应当进行初始化,即打印空格:
void game()
{
char board[ROW][COL];
//创建九宫格数组,用于处理着棋
char ret = 0;
//定义字符,用于判断输赢后跳出着棋循环
init_board(board, ROW, COL);
//将数组与行列数传递给封装函数进行初始化
print_board(board, ROW, COL);
//将初始化完成的棋盘进行打印
}
棋盘进行过初始化并打印后,就可以正式开始我们的下棋游戏了,很明显,在这一阶段要实现的功能就是玩家与电脑交替进行着棋,并在每次着棋后对棋局进行判断,若达成胜利条件则停止着棋并宣布获胜方,未达成胜利条件则继续循环着棋:
(这里的输赢判断中的字符判断暂且不考虑,后面部分的实现过程会详细讲解)
char ret