易懂|C语言小游戏(一)----猜数游戏

目录

前言
猜数判定
if else 语句
重复到猜对为止(do语句,while语句)
随机设定目标数字
srand函数大显神功
限制次数并保存输入记录
尾声
前言 施律.C语言小游戏系列预计共有10个,较适合于已经学习完C语言入门内容,并想要掌握实际编程能力的程序猿。

猜数游戏在大家初学的课本上应该都有,难度系数不大,属于一遍过的那种程序。但再小的苍蝇也有肉啊!其实猜数游戏也包含了许多实用性的技巧。长话短说,接下来听施律.为渴望提升的你讲解C语言小游戏(一)----猜数游戏。

猜数判定 先来个测试版的“猜数游戏”。通过if else语句、scanf函数键入数值和“目标数字”进行比较,并显示出比较的后果。

#include int main() { int no; int ans = 5; printf("Please guess0--9:\n"); printf("是多少呢?\n"); scanf("%d", &no); if (no > ans) printf("Too big!\n"); else if (no < ans) printf("Too small\n"); else printf("Yes!You are right!\n"); \\\n是一种转义字符,表示换行 return 0; }

本游戏设立的数是5。如果输入的数小于5,则输出Too small!;如果输入的数大于5,则输出Too big!。

if else 语句 本程序中的if语句采用以下形式。
if(表达式)语句 else if(表达式)语句 else 语句
其中的else if可以是很多个,这取决于程序猿想要设计的条件个数。
接下来我们讨论讨论多分支的方法,即用上述语句更另外2种if else 形态语句进行对比,得出优劣。话不多说,上代码!
if(no > ans) printf("Too big!\n"); else if(no < ans) printf("Too small!\n"); else printf("Yes!You are right!\n"); //1if(no > ans) printf("Too big!\n"); else if (no < ans) printf("Too small!\n"); else if (no == ans) printf("Yes!You are right!\n"); //2if(no > ans) printf("Too big!\n"); if (no < ans) printf("Too small!\n"); if (no = ans) printf("Yes!You are right!\n"); //3

我们来分析一下程序2、3较于1看看能得出什么结论。程序2较程序1追加了(no==ans)判断,这其实是非常多余的;程序3的三个if并列,无论no和ans之间的大小关系如何,程序都会对这三个条件进行判断。
接下来我们再通过图表的方式分析程序1、2、3所进行的判断,看看能得出什么结论。下面的【1】判断no>ans,【2】判断no
大小关系 no>ans时 no no==ans时
1 【1】 【1】【2】 【1】【2】
2 【1】 【1】【2】 【1】【2】【3】
3 【1】【2】【3】 【1】【2】【3】 【1】【2】【3】
由上可以得出,程序1的效率是最高的。
重复到猜对为止(do语句,while语句) 上个程序只允许玩家输入一次数值操作起来是十分无趣的。所以我们将程序改良一下,让玩家可以一直重复输入直到猜对为止。那我们该如何实现输入多次呢?我们学到的循环该派上用场了。利用do语句循环实现多次输入,代码如下:
#include int main() { int no; int ans = 7; printf("请猜一个0-9的数。\n\n"); do { printf("是多少呢?\n"); scanf("%d", &no); if (no > ans) printf("Too big!\n"); else if (no < ans) printf("Too small!\n"); else printf("Yes!You are right!\n"); } while (no != ans); return 0; }

do语句是先循环后判断的,跟它的好兄弟while语句和for语句不同(后面会讲到)。在运用到do语句的过程中要时刻记得它的末尾是有分号“ ; ”的。如上所示,do 语句的控制表达式是no!=ans,运算符!=对左边和右边的操作数的值是否不相等这一条件进行判断。如果这个条件成立,程序就会生成int型的1表示继续,不成立则生成int型的0表示循环结束。
接下来我们看看用while语句实现猜数游戏:
#include int main() { int no; int ans = 7; printf("请猜一个0-9的数。\n\n"); while (1) { printf("是多少呢?\n"); scanf("%d", &no); if (no > ans) printf("Too big!\n"); else if (no < ans) printf("Too small!\n"); else break; } printf("Yes!You are right!\n"); return 0; }

while语句是先判断后循环,跟前面的do语句的循环方式是不一样的。如上,while的控制表达式是1,所以循环会永远进行下去。这样的循环岂不是“无限循环”?那这样的循环该如何破解呢?break语句大显神功,直接强制跳出了循环语句。
随机设定目标数字 在前面的游戏中,自己设定的数自己猜显得太枯燥无趣了,要是能随机生成数字来猜则会增加很多的趣味性。仔细想想,我们好像能用rand函数来生成随机数。rand的功能是计算0-RAND_MAX(很多初学的小伙伴不知道RAND_MAX,这其实是头文件包含的一个宏,规定它的值不能小于编译环境所规定的最小数,最小为32767)的伪随机整数序列。何为“伪”?且听我一一分析。先上代码:
#include #includeint main() { int retry; //再运行一次? printf("在这个编译环境中能够生成0-%d的随机数。\n", RAND_MAX); do { printf("\n生成了随机数%d。\n", rand()); printf("再运行一次?(0)否(1)是:"); scanf("%d", &retry); } while (retry == 1); return 0; }

聪明的小伙伴可以自行ctrl+c到编译器上看看,多执行几次程序会发现生成的随机序列是一模一样的!rand函数看似生成随机实则不随机,是有一定规律可循的。为什么呢?这是因为rand函数的默认种子(rand函数是对一个叫作“种子”的基准值加以运算来生成随机数的)是1。如果我们想要生成不同的随机序列,就必须更换种子的值。
srand函数大显神功 srand函数就能解决上面所描述的窘境。它的功能是给后续调用的rand函数设置一个种子,用于生成新的伪随机数序列。如果用同一个种子的值调用本函数,就会生成相同的伪随机数序列。如果在调用本函数之前调用了rand函数,就相当于程序在一开始调用了本函数,把种子设定成了1,最后会生成一个种子值为1的序列。此外,其他库函数在运行时会无视本函数的调用。
该怎么表示呢?打个比方srand(50)和srand(40),它们生成的随机序列是不同的,且看下表:
种子为50时,生成235->666->777->231->3489.....
种子为40时,生成222->2678->2235->1463->87.....
接下来我们要想把种子从常量变成随机值,可引用头文件的time(),通过把运行程序时的时间当作种子来实现。上代码:
#include #include #include int main() { int retry; srand(time(NULL)); printf("在这个编译环境中能够生成0-%d的随机数。\n", RAND_MAX); do { printf("\n生成了随机数%d。\n", rand()); printf("再运行一次?(0)否(1)是:"); scanf("%d", &retry); } while (retry == 1); return 0; }

RAND_MAX在上文中提到它所生成的数可能是非常大的,几万几十万都有可能。那么我们该怎么控制srand生成的随机值呢?我们可以运用求余运算来实现。普及一下求余的概念。请看下面:
rand()%6是生成0到5的随机数,因为求余运算得出的结果是不会大于被余数的
、我们再对上述代码进行修改:
#include #include #include int main() { int retry; srand(time(NULL)); printf("在这个编译环境中能够生成0-%d的随机数。\n", RAND_MAX); do { printf("\n生成了随机数%d。\n", rand()); printf("再运行一次?(0)否(1)是:"); scanf("%d", &retry); } while (retry == 1); return 0; }

这样游戏玩起来就不会枯燥乏味了!但好像缺少了点紧张刺激,我们应该再对该程序进行升级----限制次数并保存输入记录。
限制次数并保存输入记录 如果游戏能够限制玩家的输入次数和保存玩家输入的值,玩家的游戏体验一定会有大幅度的升级!想到保存输入的值,我们肯定能联想到用数组保存。通过数组遍历,将玩家输入的值一一存入,并在游戏结束后呈现给玩家,让玩家知道自己猜的数字距离目标数字有多近。先上代码:
#include #include #include #define MAX_STAGE 10int main() { int i; int stage; //玩家已经操作的次数 int no; int ans; int num[MAX_STAGE]; //玩家能操作的最大次数 srand(time(NULL)); ans = rand() % 1000; printf("请猜一个0-999的整数。\n\n"); stage = 0; do { printf("还剩%d次机会。是多少呢: ", MAX_STAGE - stage); scanf("%d", &no); num[stage++] = no; if (no > ans) printf("Too big!\n"); else if (no < ans) printf("Too small!\n"); } while (no != ans && stage < MAX_STAGE); if (no != ans) printf("很遗憾,正确答案是%d。\n", ans); else { printf("Yes!You are right!\n"); printf("您用了%d次猜中了。\n", stage); } puts("\n--- 输入记录 ---"); for (i = 0; i < stage; i++) printf(" %2d:%4d %+4d\n", i + 1, num[i], num[i] - ans); return 0; }

我们来分析分析上面的代码。
(1)先讲一个错误的例子。初级程序猿经常会犯这样的错误:
int n=10; int arr[n]={0};

乍一看貌似和上面的差不多,但实际上这是错误的写法。而先定义一个宏,再在数组【】中引用宏则是正确的写法;
(2)代码num[stage++]=no; 是后置++,其利用for循环来对stage数进行增加。通过反复的循环处理,即可把玩家输入的值按顺序依次存入数组。
(3)在这段代码中我们运用了上面未曾讲到的for语句来显示输出记录。我们将这段代码拉出来单独讲解:
for (i = 0; i < stage; i++) printf(" %2d:%4d %+4d\n", i + 1, num[i], num[i] - ans);

首先把i的值设为0,当i的值小于stage时,就不断往i的值上+1,以此来让循环体运行stage次(stage的值等于玩家输入数值的次数)。
%2d %4d符号与字母之前的数字代表它们的域宽,而%+4d中的+4是将数字向右靠齐。
下面的·代表一个空格,以125为例
%4d125·
%+4d·125

尾声 以上就是施律.对本系列第一个游戏----猜字游戏的理解与分析,感谢能观看到这里的你!如果觉得本篇博客对正在学习编程的你有帮助的话,请给施律.多一点的支持与关注!接下来的10多天时间里施律.将和大家畅玩其他用编程实现的游戏,希望下次的我能为大家奉上更好的游戏,也希望下次的博客有你!


【易懂|C语言小游戏(一)----猜数游戏】

    推荐阅读