作者 谢恩铭,公众号「程序员联盟」(微信号:coderhub)。
转载请注明出处。
原文:《C语言探索之旅》全系列
经过上一课 C语言探索之旅 | 第二部分第九课: 实战"悬挂小人"游戏 之后,相信大家都或多或少都写了自己的“悬挂小人”的游戏代码吧。
这一课我们就来"终结"这个游戏吧 (听着怎么有点吓人…)。
"Yes, you are terminated."
如果你开始阅读这里,说明:
不管你是哪种情况,我都会介绍一下如何来完成这个游戏。
“说不说在我,听不听在您”~
事实上,我自己花了比想象中更多的时间来完成这游戏。
人生总是这样的,“理想丰满,现实骨感;看似美满,人艰不拆”。
但是,我还是坚信大家是有能力独自完成这个小游戏的(如果你认真学习了之前的 C语言课程),可以去查阅网上资料,花点时间(几十分钟,几小时,几天?),这并不是一次竞赛,所以不用着急。
我更希望您花了不少时间,最终实现了这个游戏; 比之您只花 5 分钟,然后就来看答案要好很多。
千万不要觉得我是一蹴而就写成这个游戏的,这个游戏虽小,但也还没简单到可以在脑中构思好一切,然后“下笔如有神”: 我也是一步步写出来的。
我们将会分 2 步来介绍我们的解方:
首先我们会演示如何一步步写游戏的主体部分,一开始我们会只有一个猜测的单词,而且是固定的;我选了 BOTTLE(表示“瓶子”),因为我们要测试对于单词中有大于等于两个相同字母的情况是否处理正确了(BOTTLE 中有 2 个 T)。
然后我们会演示如何加入词库的处理程序,以便每一轮游戏可以从词库中随机抽取一个单词。
牢记:重要的不是结果,而是我们思考的方式和过程。
分析 main 函数
大家都知道,我们的 C语言程序都是由 main 函数作为入口的。
我们也不要忘了引入一些标准库的头文件:stdio.h,stdlib.h,ctype.h(为了 toupper 函数)。
因此,我们的程序一开始会是这样的:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>int main(int argc, char* argv[])
{return 0;
}
是不是很简单啊,慢慢来么。
我们的 main 函数将控制游戏的大部分运作,并且调用我们将要写的不少函数。
我们来声明一些必要的变量吧。这些变量也不是一次就能全部想到的,都是写一点,想到一些。“罗马不是一日建成的, 小人也不是一日能悬挂完的”。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>int main(int argc, char* argv[])
{char letter = 0; // 存储用户输入的字母char secretWord[] = "BOTTLE"; // 要猜测的单词int letterFound[6] = {0}; // 布尔值的数组。数组的每一个元素对应猜测单词的一个字母。0 = 还没猜到此字母, 1 = 已猜到字母int leftTimes = 7; // 剩余猜测次数(0 = 失败)int i = 0; // 为了遍历数组,需要一个下标return 0;
}
上述的变量中,起到关键作用的就是 letterFound 这个 int 型数组了。这个数组用于表示猜测的单词中哪些字母已经猜到,哪些还没猜到。
一开始,我们实现得简单些:我们的单词 BOTTLE 有 6 个字母,因此我们的数组就固定是 6 个元素的数组。
如果元素为 0,表示对应的那个字母还没猜到;如果为 1,则表示已猜到。随着游戏的进行,这个数组的元素值会被修改。
例如,如果当下我们玩游戏直到:
B*TT*E
那么,letterFound 这个数组的值应该是这样:
101101
之后我们要测试游戏的一轮是否已经胜利也就比较简单了:只需要测试 letterFound 数组的所有元素是否都等于 1。
我们就来写判断一轮是否胜利的函数吧,取名为 win(表示 “胜利”)好了。
int win(int letterFound[])
{int i = 0;int win = 1; // 1 为胜利,0 为失败for (i = 0 ; i < 6 ; i++){if (letterFound[i] == 0)win = 0;}return win;
}
可以看到,我们的 win 函数的参数是一个 int 型数组,我们在 main 函数中调用 win 函数时,会将我们的 letterFound 数组传给它。
这个函数很简单:遍历数组,只要还有一个元素为 0,那游戏还没胜利;如果所有元素都为 1,则游戏胜利。
为了与此函数搭配,我们还需要写一个函数,起名叫 researchLetter,这个函数将有两个功能:
返回一个布尔值(在 C语言里用 int 型表示),用于表示所猜的字母是否存在于单词中。
更新 letterFound 数组的元素,如果所猜的字母在单词中,那么就把对应的元素值修改为 1。
int researchLetter(char letter, char secretWord[], int letterFound[])
{int i = 0;int correctLetter = 0; // 0 表示字母不在单词里,1 表示字母在单词里// 遍历单词数组 secretWord,以判断所猜字母是否在单词中for (i = 0 ; secretWord[i] != '