一:游戏要求

1.电脑自动生成1~100随机数字

2.玩家猜数字,在猜数字过程中,根据猜数字的大小,根据猜数据的大小,给出大了还是小了的反馈,直到猜对游戏

二:随机数的生成

要完成猜数字游戏,最重要的就是要生成随机数,那怎么才能生成随机数呢?

2.1 rand函数

基于上述问题,就要介绍一个C语言函数了—–rand,这个函数是可以生成随机数的,函数原型如下:

int rand(void);//void 指的是这个函数不含参数

rand函数会返回一个伪随机数(为什么成为伪,请看后续讲解),这个随机数的范围是0~RAND_MAX,这个RAND_MAX的大小是依赖编译器实现的,但是大部分编译器是32767.

rand函数的使用要包含一个头文件:stdlib.h

这里我先演示一下rand函数使用:随机生成五个数字

int main(){printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());return 0;}

看到这也许会疑问,为什么我会贴两张一模一样的运行结果呢?

其实着是我用上面代码,运行两次的结果,也就是说rand产生的值是随机的,但是是相对随机的

这时就要求我们就深入了解rand的机制,明白它为什么会产生随机值,随机值为什么又是相对的?

rand函数由上述代码可以看出生成的随机数是伪随机数,而伪随机不是真正的随机数,是通过一种算法生成的随即数,真正的随机数是无法预测下一个值是多少的。而rand函数是对一个叫“种子”的基准值进行运算生成的随机数。

之所以前面每次程序产生的随机数序列是一样的,那是因为rand函数生产的随机数的默认种子是1。如果要生成不同的随机数,就要让“种子”发生变化。

2.2 srand

正巧是是,C语言中有一个函数叫srand,用来初始化随机数的生成器(初始化种子基准值),srand的原型如下:

void srand(unsigned int seed);

程序在调用rand函数之前先调用srand函数,通过srand函数的参数seed来设置rand函数生成随机数的时候的种子,只要种子发生变化,每次生成的随机数的序列就会发生变化。

也就是说,给srand的种子如果是随机的,rand就能生成随机数;在生成随机数的时候又需要一个随机数,这似乎像套娃一样,没有尽头了

2.3 time

srand的种子是随机的,其中一层意思就是,它的种子是一直在变化的,才能保证rand的随机数列在变化。这是,我们可以想一下,什么是一直变化,且在短时间内是不会重复的?

此时,各位不妨看一下你们手机或电脑的时间,是不是每一秒都在变化?

所以,在程序中我们一般使用程序运行的时间作为种子的,因为时间时刻在变化。

time_t time (time_t* time);

time函数会返回当前的日历时间,其实返回的是1970年1月1日0时0分0秒到现在程序运行时间的插值,单位是秒。返回的类型是time_t类型的,time _t类型的本质上其实就是32位或64位的整数类型。

time函数的参数是timer,如果是非NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去

如果timet是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。

time函数需要包含头文件:time.h

如果只是让time函数返回时间戳,我们可以这样写:

time(NULL);
int main(){srand((unsigned int)time(NULL));printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());return 0;}

:使用srand生成种子之后,使用rand一次性产生大量的随机数,构成一个随机数列,所以srand不用频繁使用,一次运行的程序中调用一次就可以了

2.4随机数的范围

如果我们要生成0~99之间随机数,方法如下:

rand()%100//余数是0~99

如果要生成1~100之间的随机数,方法如下:

rand()%100 + 1 //%100的余数是0~99,,0~99+1就是1~100

如果要生成100~200之间的数字

100 + rand() % (200-100+1) //%101生成0~100之间的数字,+100就是100~200

由此可得出:生成a~b的随机数,方法如下:

a + rand()%(b-a+1)

三:游戏设计

3.1菜单

首先,我们应该打印一个游戏菜单,让玩家选择是否进入游戏,是退出游戏还是继续游戏?

其次就是,这个菜单时玩家已进入程序就会立即出现的,在这之前玩家还无需输入什么,菜单出现后,可以根据菜单的提示,做出相应的选择,所以这里就要用do while循环

printf("*******************\n");printf("***** 0. exit *****\n");//0退出printf("***** 1. play *****\n");//1游戏printf("*******************\n");

为了让主函数更加简洁,易懂,让菜单可以重复利用,我们可以将菜单封装到一个函数中

3.2核心代码实现

核心代码的操作与菜单类似,封装到一个函数中

而在核心代码之前,应该有让玩家选择输入1还是0,输入1,才会进行游戏

有一个问题,srand生成的种子是放在game函数中,还是main函数中呢?

1.从调用次数来说,放在game函数中,如果玩家一次性玩多次,会被调用多次,而放在main函数中,玩家调用一次程序,在退出游戏之前,srand就只调用一次。从次数来说,放在main函数中好。

2.考虑极端情况,放在game中,如果玩家第一次玩游戏是一次性就猜中了,然后有选择继续玩,这是game就被调用第二次,srand就会根据当前时间,再次生成随机数,但是一次性猜中的情况下,两局游戏距离时间可能是十分短,所以srand产生的种子可能相同,那么随机数就是伪随机了。而放在main函数中,即使两次时间距离短暂,但是既然没有退出程序,那下次再猜数字就是从生成好的随机数列中继续向下选取数字,在一列随机数中,两个随机数不会相同。

综上,放在main函数中

四:代码

void menu(){printf("*******************\n");printf("***** 0. exit *****\n");//0退出printf("***** 1. play *****\n");//1游戏printf("*******************\n");}void game(){int num = rand() % 100 + 1;int guess = 0;while (1){printf("请输入您猜的数字:");scanf("%d", &guess);if (guess  num){printf("您猜大了\n");}else{printf("恭喜您,猜对了\n");break;}}}int main(){int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请输入您的选择:");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("退出游戏");break;default:printf("输入错误,请重新输入");}} while (input);}

五:游戏进阶

以上是猜数字游戏的基础版,再次之上还可以加各种限制要求,例如猜一定的次数就不可以再猜了……