前面介绍过很多的C语言常识,但是我们都知道“兴趣是最好的老师”,所以,今天我们用之前讲过的一些知识,加上部分新补充的知识点,写一个“猜数字”的小游戏,来丰富我们的编程学习生活,感受来自C语言的趣味性。
目录
1.猜数字游戏的大致流程
2.游戏实现的思路
3.随机数生成
3.1rand
3.2srand
3.3time
3.4随机数范围设置
4.猜数字游戏的代码实现
5.猜数字游戏的优化
1.猜数字游戏的大致流程
首先由计算机产生一个随机数,并给出这个随机数所在的区间,然后由玩家来猜测这个数,如果玩家猜中这个数,则显示成功并结束本轮游戏,如果猜测次数超过8次,则显示猜测失败并结束本轮游戏。
2.游戏实现的思路
我们在写编程题或者小游戏代码时,最重要的就是理清思路——主体是什么?为了实现目的要创建哪些函数?函数的功能都是什么?只有当我们心中有了一个大体的框架,知道该做些什么时,我们才能更高效地编写代码,完成程序设计。
猜数字游戏的算法如下:
1.提供游戏菜单,由玩家选择是否进行游戏:按“1”开始游戏,按“0”推出游戏,按其他则显示“选择错误,请重新选择”。
2.开始游戏后,先初始化猜测次数count = 0;
3.重复执行下述操作,直到count达到8次:
3.1玩家输入一个数guess(进行猜测);
3.2count++;
3.2如果guess等于secret(计算机产生的随机数),跳出循环;否则显示“错了,请重新猜!你还有8-count次猜测次数,请把握好机会!”
4.如果count达到8次,则显示“超过次数,游戏结束!”;否则,显示“恭喜,猜对了!共猜测count次!”
如上面所示,这就是猜数字游戏大体框架的算法呈现。
我们在思考大体框架时不用过多在意具体函数的实现方法,可以先起个能表达其功能的函数名并把它放在需要的位置。(说白了就是先搞一个空壳函数占位置,等到大体框架调试完毕不再有问题后,再去实现这些空壳函数)大体框架代码如下:
#iclude<stdio.h>int main()
{int secret;//随机数怎么建立呢?我们好像暂时也不清楚,那么就先假设一个空壳的,不用在意它。int input;do{ //menu函数在调试大体框架时,也可以是空壳函数menu();//打印游戏菜单。我们建立函数可以让主函数不至于太过冗长,而且增加了代码的可读性,使程序模块化。printf("请选择:>");scanf("%d", &input);switch(input){case 1:guess(secret);//guess是用来猜测并判断是否正确的函数,这里也是空壳函数break;case 0:printf("游戏结束\n");break;default:printf("选择错误,请重新选择\n");break;}}while(input);return 0;
}
上面的guess函数就是个空壳函数,我们可以在把主体框架完成后再去实现。而guess函数的功能就是:
①guess(玩家猜测数)= secret,则显示“恭喜,猜对了!同猜测count次!”;
②guess(玩家猜测数)!= secret,则显示“错了,请重新猜!你还有8-count次猜测机会,请把握好机会!”
guess函数的代码实现如下:
void guess(int secret)
{int guess= 0, count = 0;do{printf("请输入一个整数>:");scanf("%d", &guess);count++;if(guess == secret) break;else pritnf("错了,请重新猜!你还有%d猜测次数,请把握好机会\n",8-count);}while(count<8);if(count < 8)printf("恭喜,猜对了!共猜测%d次!\n",count);elseprintf("超过次数,游戏结束!\n");}
menu函数的代码实现如下:
void menu()
{printf("***********************\n");printf("****** 1. play ******\n");printf("****** 0. exit ******\n");printf("***********************\n");
}
3.随机数生成
上面我们已经把大体框架和空壳函数都实现,按照正常情况我们的代码已经完成了,只需要调试使其能正常运行即可,但是在这个游戏中我们还需要补充一个新的知识点——随机数的生成。
3.1rand
C语言提供了随机数生成函数rand,该函数返回0~RAND_MAX的一个随机整数,RAND_MAX是在头文件stdlib.h中定义的符号常量,其值与机器字长和编程环境有关,一般为2^15-1或2^31-1。
rand函数原型为:
int rand (void);
#include <stdio.h>
#include <stdlib.h>
int main()
{printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());return 0;
}
大家可以测试两次上面的数据,然后大家会发现随机数的建立到这一步还没有结束。😏
下面是我的代码两次运行结果,大家品一品
我们可以看到虽然一次运行中产生的5个数字是相对随机的,但是下一次运行程序生成的结果和上一次一模一样,这就说明有点问题。 如果再深入了解一下,我们就不难发现,其实rand函数生成的随机数是伪随机的,伪随机数不是真正的随机数,是通过某种算法生成的随机数,而真正的随机数的是无法预测下一个值是多少的。
rand函数是对一个叫“种子”的基准值进行运算生成的随机数。 之所以前面每次运行程序产生的随机数序列是一样的,那是因为rand函数生成随机数的默认种子是1。 如果要生成不同的随机数,就要让种子是变化的。
3.2srand
C语言提供了库函数srand初始化随机种子,例如可以调用库函数time得到当前的系统时间,将当前系统时间作为随机种子。
srand函数的原型为:
void srand (unsigned int seed);
程序中在调用rand函数之前先调用srand函数,通过srand函数的参数seed来设置rand函数生成随 机数的时候的种子,只要种子在变化,每次生成的随机数序列也就变化起来了。那也就是说给srand的种子是如果是随机的,rand就能生成随机数;在生成随机数的时候又需要一个随机数,这就矛盾了,该怎么解决呢?
3.3time
C语言提供一个函数time,用来获得系统时间。
time函数的原型为:
time_t time (time_t* timer);
time函数会返回当前的日历时间,其实返回的是1970年1月1日0时0分0秒到现在程序运行时间之间的差值,单位是秒。返回的类型是time_t类型的,time_t 类型本质上其实就是32位或者64位的整型类型 。
time函数的时候需要包含头文件:time.h
综合上面三个函数及介绍,则随机数生成代码实现为:
srand((unsigned int)time(NULL));//初始化随机种子
rand( );//产生随机数
3.4随机数范围设置
既然是随机数,那么就会从0~RAND_MAX中随机生成一个数字,那我们能猜对吗?😀答案是显然的,别说是八次机会,就是八十次都不一定能猜对。所以,为了照顾玩家的游戏体验,我们也必须设置随机数的范围,让它更为科学和合理。
如果我们要生成0~99之间的随机数,方法如下:
rand() %100;//余数的范围是0~99
如果我们要生成1~100之间的随机数,方法如下:
rand()%100+1;//%100的余数是0~99,0~99的数字+1,范围是1~100
如果我们要生成a~b之间的随机数,方法如下:
a + rand()%(b-a+1)
4.猜数字游戏的代码实现
前面的准备工作已经做完了,那么就整合所有模块,一起来见证我们努力的成果吧!
#include<stdio.h>
#include <stdlib.h>
#include <time.h>//记得检查所需的函数头文件都引用没有哦 void menu()
{printf("***********************\n");printf("****** 1. play ******\n");printf("****** 0. exit ******\n");printf("***********************\n");
}void guess(int secret)
{int guess = 0, count = 0;do{printf("请输入一个整数>:");scanf("%d", &guess);count++;if(guess == secret) break;else printf("错了,请重新猜!你还有%d猜测次数,请把握好机会\n\n",8-count);}while(count<8);if(count < 8)printf("恭喜,猜对了!共猜测%d次!\n",count);elseprintf("超过次数,游戏结束!\n");}int main()
{srand((unsigned int)time(NULL));int input = 0;srand((unsigned int)time(NULL));do{ int secret = rand() %100;//生成0~99之间的随机数 //menu函数在调试大体框架时,也可以是空壳函数menu();//打印游戏菜单。我们建立函数可以让主函数不至于太过冗长,而且增加了代码的可读性,使程序模块化。printf("请选择:>");scanf("%d", &input);switch(input){case 1:guess(secret);//guess是用来猜测并判断是否正确的函数,这里也是空壳函数break;case 0:printf("游戏结束\n");break;default:printf("选择错误,请重新选择\n");break;}}while(input);return 0;
}
上面的代码进行了细微的调整——把rand的随机种子初始化放在do之前,然后把随机数的生成放在do…while语句中,这样我们每一轮游戏所猜的数字都是不同的,且不必重复初始化随机种子。
5.猜数字游戏的优化
我们玩几局就会发现,虽然限制了随机数的范围,但想在8次机会中猜对还是有些难度,所以为了我们亲爱的玩家,我们就再降低难度——当他们猜完数字后,给他们提示:“猜大了”或者“猜小了”
优化后的代码如下:
#include<stdio.h>
#include <stdlib.h>
#include <time.h>//记得检查所需的函数头文件都引用没有哦 void menu()
{printf("***********************\n");printf("****** 1. play ******\n");printf("****** 0. exit ******\n");printf("***********************\n");
}void guess(int secret)
{int guess = 0, count = 0;do{printf("请输入一个整数>:");scanf("%d", &guess);count++;if(guess == secret) break;else if(guess > secret){if(count != 8) printf("猜大了,请重新猜!你还有%d猜测次数,请把握好机会\n\n",8-count);else printf("可惜最后还是猜大了\n");} else{if(count != 8) printf("猜小了,请重新猜!你还有%d猜测次数,请把握好机会\n\n",8-count);else printf("可惜最后还是猜小了\n");}}while(count<8);if(count < 8)printf("恭喜,猜对了!共猜测%d次!\n",count);elseprintf("不好意思,次数已用完,游戏结束!\n");}int main()
{srand((unsigned int)time(NULL));int input = 0;srand((unsigned int)time(NULL));do{ int secret = rand() %100;//生成0~99之间的随机数 //menu函数在调试大体框架时,也可以是空壳函数menu();//打印游戏菜单。我们建立函数可以让主函数不至于太过冗长,而且增加了代码的可读性,使程序模块化。printf("请选择:>");scanf("%d", &input);switch(input){case 1:guess(secret);//guess是用来猜测并判断是否正确的函数,这里也是空壳函数break;case 0:printf("游戏结束\n");break;default:printf("选择错误,请重新选择\n");break;}}while(input);return 0;
}
猜数字小游戏到这里算是结束喽,不知道大家学习的过程辛苦不辛苦,反正我是痛并快乐着的🙂🙂🙂
关于猜数字的更多玩法和可能性,就全权交由聪明的大家了。当然大家有啥好想法又不想一个人搞的,也可以在评论区发出来,大家一起交流交流,研究研究。