目录
要想完成猜数字游戏,⾸先得产⽣随机数,那怎么产⽣随机数呢?
1. 随机数的生成方法
我们可以通过rand函数,srand函数和time函数这3个工具来完成真随机数的生成
1.1 rand()函数
1.1.1 函数原型
C语⾔提供了⼀个函数叫 rand (使用时需要包含头文件<stdlib.h>),这函数是可以⽣成随机数的,函数原型如下所示:
int rand (void);
1.1.2 函数功能
rand函数会返回⼀个伪随机数,这个随机数的范围是在0~RAND_MAX之间,这个RAND_MAX的⼤⼩是 依赖编译器上实现的,但是⼤部分编译器上是32767。
下面我们调用3次rand函数来测试一下:
为什么说rand函数返回的随机数是伪随机数呢?我们让代码再运行一次看看:
我们发现,即使是把代码的内容改了一下,两次运行产生随机数是一模一样的,这就是为什么说这是伪随机的。
rand的特点总结:
1. 使用rand函数时,要包含头文件<stdlib.h>。
2. 使用时不需要输入参数,rand函数会返回一个伪随机值
3. 随机数范围通常在0 ~ 32767
4. 同一次程序运行中,多个rand产生的随机数是不同的;在不同次程序运行中,对应出现次序的rand产生的“随机数”是相同的。
再深⼊了解⼀下,rand函数是对⼀个叫“种子”的基准值进⾏运算⽣成的随机数。 之所以前⾯每次运⾏程序产⽣的随机数序列是⼀样的,那是因为rand函数⽣成随机数的默认种⼦是1。 如果要⽣成不同的随机数,就要让种⼦是变化的。
1.2 srand()函数
1.2.1 函数原型
C语⾔中⼜提供了⼀个函数叫 srand,⽤来来初始化随机数的⽣成器的,srand的原型如下:
void srand (unsigned int seed);
1.2.2 函数功能
在调⽤rand函数之前先调⽤srand函数,通过srand函数的参数seed来设置(或改变)rand函数生成随机数时的种子。
上次的rand的种子默认是1,我们用srand把种子改成2试试:
我们发现,把种子改成2后,第3运行的结果果然与前两次不一样了。
那也就是说给srand的参数是如果是动态的,rand就能⽣成随机数。但在rand⽣成随机数的时候又需要srand有动态的随机数,这就⽭盾了。
所以有srand函数还不够,我们还要保证srand的参数每次运行都是不同的;时间是每一秒都不同的,那我们要怎样利用时间呢?
1.3 time()函数
1.2.1 函数原型
在C语⾔中有⼀个函数叫 time (使用时需要包含头文件<time.h>),就可以获得这个时间,time函数原型如下:
time_t time (time_t* timer);
time_t 是什么类型?让我们打开头文件<time.h>看看:
//VS2022 上time_t类型的说明
#ifndef _CRT_NO_TIME_T
#ifdef _USE_32BIT_TIME_T
typedef __time32_t time_t;
#else
typedef __time64_t time_t;
#endif
#endif
typedef long __time32_t;
typedef __int64 __time64_t;
从最后两行代码可以发现,time_t 其实是一种整形的宏定义。所以time函数的返回值是一个整数。
1.1.2 函数功能
time 函数会返回当前的⽇历时间,其实返回的是1970年1⽉1⽇0时0分0秒到当前程序运行时间之间的差值,单位是秒。time函数返回的这个时间差也被叫做时间戳,而它是从1970年1⽉1⽇0时0分0秒开始计时的。
如果 timer 是NULL,就只返回这个时间戳。
(了解即可)如果是⾮NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。
值得注意的是,srand函数的参数类型是unsigned int,而time的函数返回类型是time_t。虽然都是整形,但是我们最好把类型强制转化一下,写成 :srand( (unsigned int) time(NULL) ) ;
int main()
{
srand((unsigned int)time(NULL));
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
return 0;
}
我们来验证一下效果:
现在不同次程序运行生成的都不同了,终于做到了真正的随机数生成。
1.4 设置随机数的范围
我们知道,如果m除以n,则余数的范围在0 ~ n-1。
如果果我们要⽣成0~99之间的随机数,⽅法如下:
rand() %100;
如果要⽣成1~100之间的随机数,⽅法如下:
1+rand()%100; 等于 1+rand()%(100-1+1)
如果要⽣成100~200的随机数,⽅法如下:
100 + rand()%(200-100+1);//右边除了101,余数是0~100
所以如果要⽣成a~b的随机数,⽅法如下:
a + rand()%(b-a+1);
2. 猜数字游戏
写⼀个猜数字游戏
游戏要求:
1. 电脑⾃动⽣成1~100的随机数
2. 玩家猜数字,猜数字的过程中,根据猜测数据的⼤⼩给出⼤了或⼩了的反馈,直到猜对,游戏结束
2.1 普通版:结构逻辑解析
需要用到的结构:
1. 游戏菜单:给予玩家操作指示
2. main函数:使用分支语句使得玩家可以进行选择操作。因为玩家胜利后还能继续游戏的,所以还要用到循环结构。
3. 游戏核心程序:1.生成符合游戏范围的随机数。2. 对玩家输入的数字与要猜的数进行比较,猜大了或猜小了都要提示。
2.1.1 程序代码
//游戏菜单
void menu()
{
printf("———————————————— 猜数字 —————————————————\n");
printf("###############输入1->开始################\n");
printf("###############输入0->离开################\n");
printf("————————————— (范围1~100) ———————————————\n");
printf("请输入数字:");
}
//游戏核心程序
void guess_number()
{
//1.生成并控制随机数
int r = rand() % 100 + 1;
//2.猜数字
int guess = 0;
while (1) //细节点1!!!
{
scanf("%d", &guess);
if (guess < r)
printf("猜小了\n");
else if (guess > r)
printf("猜大了\n");
else
{
printf("恭喜你,猜对了\n");
break;
}
}
}
int main()
{
int choice = 0;
srand((unsigned int)time(NULL)); //细节点2!!!
do
{
//1.游戏菜单
menu();
//2.选择分支程序
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("\n游戏开始\n");
//3.游戏程序
guess_number();
printf("\n再接再厉\n");
break;
case 0:
printf("\a———————————————— 游戏结束 —————————————————\n");
break;
}
} while (choice); //细节点3!!!
return 0;
}
2.1.2 细节答疑
细节1:为什么此次循环条件写作1?
答:因为游戏要求让玩家猜到才结束,猜不到就要一直猜。当条件表达式的值非0时就能死循环,所以写为1,最后会因为猜对了break出来。(如果不想一直循环,可以像下面的进阶版那样用cnt--限制次数)
细节2:为什么“srand((unsigned int)time(NULL));”要写在main函数,而不写在游戏核心程序guess_number里面 ?
答:srand(time)是防止下次程序运行的时候随机数相同,rand在同一次程序中多次调用的值是不同的。因为继续下一次游戏是循环调用,而不是不同次程序运行调用。把srand(time)放在核心游戏程序guess_number里面虽然可以,但是有点多余调用了,会增加一点运行的时间。
细节3:为什么此处循环条件是“choice != 0”,而不是“choice == 1” ?
答:菜单上写着输入1就玩游戏,输入0就退出,choice等于1会玩游戏,玩完游戏还会问玩家还玩不玩。所以看上去条件是“choice==1”让玩家继续玩没问题,但实际上玩家可能会输入除了0和1以外的值,这时候需要玩家重新输入,所以条件应该是“choice!=0”。
————》
case 0 那里我用了个转义字符\a,这个是我用来模拟结束的声音的,有没有都无所谓,如果你想学习转义字符的知识,可以去看我往期的博客:转义字符的详细介绍(对初学者有帮助)
————》
2.2 拓展进阶版(游戏失败会有惩罚)
如果我们给猜数字游戏设置试错次数,规定次数内也猜不出来则会强制关机,如果用户做什么能满足你需求的事你就取消关机。
添加的关机程序:
该程序用到的system函数需要包含头文件<windows.h>。下面是代码:
void closedown()
{
char s[20] = { 0 };
system("shutdown -s -t 60"); //强制关机的代码
while(1)
{
printf("注意,你的电脑将在60秒内关机。如果你说“我要玩明日方舟”,就取消关机\n");
scanf("%s", s);
if (strcmp(s, "我要玩明日方舟") == 0)
{
system("shutdown -a"); //取消关机的代码
break;
}
}
}
或者写成:
void closedown()
{
char s[20] = {0};
again:
system("shutdown -s -t 60"); //强制关机
printf("注意,你的电脑将在60秒内关机。如果你说“我要玩明日方舟”,就取消关机\n");
scanf("%s", s);
if (strcmp(s, "我要玩明日方舟") == 0)
{
system("shutdown -a"); //取消关机
}
else
{
goto again;
}
}
while循环版和goto语句版都可以,你只需要写其中一个。
修改的游戏核心程序(加上试错次数,失败就进入关机程序):
void guess_number()
{
int r = rand()%100+1;
int guess = 0;
int cnt = 5; //设置试错次数
while (cnt--)
{
printf("请猜数字,你还有%d次机会:", cnt+1);
scanf("%d", &guess);
if (guess < r)
printf("猜小了\n");
else if(guess > r)
printf("猜大了\n");
else
{
printf("恭喜你,猜对了\n");
break;
}
}
if (cnt < 0)
{
printf("失败了,答案是%d\n", r);
closedown(); //如果失败,最终cnt会等于-1,此时进入关机程序
}
}
剩下的main函数和菜单menu都不用修改,这样最终版本就做好了
标签:rand,srand,函数,拔高,printf,初学者,随机数,time From: https://blog.csdn.net/2301_80030290/article/details/140758219