首页 > 其他分享 >随机数函数 和 猜数字游戏(c语言初学者拔高)

随机数函数 和 猜数字游戏(c语言初学者拔高)

时间:2024-07-29 20:53:38浏览次数:17  
标签:rand srand 函数 拔高 printf 初学者 随机数 time

目录

1. 随机数的生成方法

1.1 rand()函数

1.1.1 函数原型

1.1.2 函数功能

1.2 srand()函数

1.2.1 函数原型

1.2.2 函数功能

1.3 time()函数

1.2.1 函数原型

1.1.2 函数功能

1.4 设置随机数的范围

2. 猜数字游戏

2.1 普通版:结构逻辑解析

2.1.1 程序代码

2.1.2 细节答疑

2.2 拓展进阶版(游戏失败会有惩罚)


要想完成猜数字游戏,⾸先得产⽣随机数,那怎么产⽣随机数呢?

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

相关文章

  • 【小知识】随机的世界——一文带你了解随机数
    【小知识】随机的世界——一文带你了解随机数1.引入2.rand函数3.srand函数1.引入    在运行程序时,我们时常需要随机数据。比如游戏中的抽卡。这个时候我们就需要随机数了。2.rand函数在实现取一个随机数时,我们通常需要用到rand函数。取一个a~b之间的随机数示例......
  • unity游戏源码和配套教程:三维的美好场景,完全免费和开源,教程完整详细,适合初学者入门
    源码(含配套教程)在夸克网盘(完全免费,完全开源,完整详细):夸克网盘分享夸克网盘是夸克推出的一款云服务产品,功能包括云存储、高清看剧、文件在线解压、PDF一键转换等。通过夸克网盘可随时随地管理和使用照片、文档、手机资料,目前支持Android、iOS、PC、iPad。https://pan.quark.cn/s/......
  • 入门C语言Day19——猜随机数游戏
    之前学了分支与循环的很多内容,所以今天可以试着来运用之前的知识来试着写一些有趣的程序——猜随机数游戏。(当然,还有一些知识要补充。)这个多数人都应该有所耳闻,就是规定一个数字范围,然后去猜数字,根据反馈去调整所猜的数字直到猜对。所以我们假定电脑生成的随机数为1~100,并且......
  • C++初学者指南-6.函数对象--lambdas(基础)
    C++初学者指南-6.函数对象–lambdas(基础)文章目录C++初学者指南-6.函数对象--lambdas(基础)提醒:函数类和对象Lambdas变量捕获保存闭包通用Lambdas(C++14)广义捕获(C++14)相关内容幻灯片提醒:函数类和对象类至少提供一个operator()(…){…}函数能像一个......
  • SpringBoot源码初学者(二):SpringBoot事件监听器
    ps:真正适合阅读源码的新手来看的SpringBoot源码讲解,如果你真的想读懂SpringBoot源码,可以按照以下推荐的方式来阅读文章打开ide,打开SpringBoot源码,跟着文章一起写注释,写自己的注释不要过于纠结没讲到的地方,毕竟SpringBoot源码那么多,想全讲完是不可能的,只要跟着文章认真阅......
  • C语言100道基础拔高题(1)
    1.有1,2,3,4这几个数字,问能组成多少个互不相同且无重复数字的三位数?    解题思路:首先输出由这几个数字所组成的所有三位数,接着再设置条件,使其输出的三位数不重复,下面我们来看下源代码。值得注意的是:所以题目的代码都是作者自行编写,如有更好的思路或者代码的优化,还请......
  • C语言100道基础拔高题(2)
    1.求两个数的最小公倍数和最大公约数        解题思路:求最小公倍数可以通过两个数的积再除以最大公约数来计算。而最大公约数则可以通过辗转相除法(又名欧几里得算法)来得到。源代码如下:#include<stdio.h>intmain(){ //程序分析:最小公倍数=两个数的积除以......
  • C语言100基础拔高题(3)
    1.利用递归函数调用方式,将所输入的5个字符,以相反顺序打印出来。                 解题思路:通过反复调用一个打印最后一个元素的函数,来实现此功能。源代码如下:#include<stdio.h>voidoposize(charstr[],intlen);intmain(){ //利用......
  • 随机数生成
    目录一、rand函数二、srand函数三、time函数一、rand函数    我们想要生成一个随机数,可以使用rand函数,rand函数定义在<stdlib.h>头文件中。它的函数原型如下:intrand(void)    它能返回一个0~RAND_MAX之间的整数,RAND_MAX的大小由编译器厂商设定,但......
  • 初学者如何快速上手多种AI工具?从零到精通:AI工具新手入门指南与精选集合
    在工作和生活中,我经常使用各种各样的人工智能工具,如AI写作软件、AI语音助手、AI绘图工具等。我发现,这些工具能够极大地提高工作效率并简化日常生活。作为一名AI工具的忠实爱好者,我整理了大量珍贵的AI资源网站,完全适用于国内用户,希望能助你一臂之力,轻松提升你的工作和学习效率,今......