掌握了前⾯学习的这些知识,我们就可以写⼀些稍微有趣的代码了,⽐如:写⼀个猜数字游戏
游戏要求:
- 电脑自动生成1~100的随机数
- 玩家猜数字,猜数字的过程中,根据猜测数据的大小给出大了或小了的反馈,直到猜对,游戏结束
要想完成猜数字游戏,⾸先得产⽣随机数,那怎么产⽣随机数呢?
1 rand 函数
C语⾔提供了⼀个函数叫 rand,这函数是可以⽣成随机数的,函数原型如下所⽰:
1 int rand (void);//void的意思就是(无),就是不需要参数,不用传参。
rand函数会返回⼀个伪随机数,这个随机数的范围是在0~RAND_MAX之间,这个RAND_MAX的⼤⼩是根据编译器来实现的,在不同的编译器上可能会有不同的差异,但是在⼤部分编译器上是32767。
rand函数的使⽤需要包含⼀个头⽂件是:stdlib.h
那我们就测试⼀下 rand 函数,这⾥多调⽤⼏次,产⽣5个随机数:
#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。如果要⽣成不同的随机数,就要让种⼦是变化的。
2 srand函数
C语⾔中⼜提供了⼀个函数叫 srand,⽤来初始化随机数的⽣成器的,srand的原型如下:
void srand (unsigned int seed);
程序中在调⽤ rand 函数之前会先调用 srand 函数,通过 srand 函数的参数seed来设置rand函数⽣成随机数的时候的种⼦,只要种⼦在变化,每次⽣成的随机数序列也就变化起来了。
那也就是说给srand的种⼦是如果是随机的,rand就能⽣成随机数;在⽣成随机数的时候⼜需要⼀个随机数,这就⽭盾了。其实也不是要给 srand 传一个随机值,只需要传一个一直在变化的值就够了。
3 time函数
在程序中我们⼀般是使⽤程序运⾏的时间作为种⼦的,因为时间时刻在发⽣变化的。
在C语⾔中有⼀个函数叫 time ,就可以获得这个时间,time函数原型如下:
time_t time (time_t* timer);
time 函数会返回当前的⽇历时间,其实返回的是1970年1⽉1⽇0时0分0秒到现在程序运⾏时间之间的差值,单位是秒。返回的类型是time_t类型的,time_t 类型本质上其实就是32位或者64位的整型类型。
time函数的参数 timer 如果是⾮NULL(非空)的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。
如果 timer 是NULL(空指针),就只返回这个时间的差值。(这里理解不了问题也不大) time函数返回的这个时间差也被叫做:时间戳。
时间戳其实就是一段数字,这个数字转换一下就可以转换成时间,上面有超链接大家可以点进去自行体会一下就能理解了。浏览器搜索时间戳也会有
当然使用 time 函数的时候需要包含头⽂件:time.h
如果只是让time函数返回时间戳,我们就可以这样写:
time(NULL);//调⽤time函数返回时间戳,这⾥没有接收返回值
那我们就可以让⽣成随机数的代码改写成如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
//使⽤time函数的返回值设置种⼦
//因为srand的参数是unsigned int类型,我们将time函数的返回值强制类型转换
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函数是不需要频繁调用的,⼀次运行的程序中调用⼀次就够了。
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)//余数的范围是0~100,加100后就是100~200
所以如果要⽣成a~b的随机数,⽅法如下:
a + rand()%(b-a+1)
5.猜数字游戏实现
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void meun()
{
printf("**************************\n");
printf("****** 1. 开始游戏 ******\n");
printf("****** 0. 结束游戏 ******\n");
printf("**************************\n");
}
void gaem()
{
int guess = 0;
int z = 0;
int r = rand() % 100 + 1;
while (1)
{
printf("猜数字:");
z++;
scanf("%d", &guess);
if (guess > r)
{
printf("猜大了\n");
}
else if (guess < r)
{
printf("猜小了\n");
}
else
{
printf("猜对了~~~\n");
printf("恭喜你一共用了%d次猜对了\n", z);
break;
}
}
}
int main()
{
int z = 0;
srand((unsigned int)time(NULL));
do
{
//打印菜单
meun();
printf("请选择 :>");
scanf("%d", &z);
switch (z)
{
case 1:
printf("游戏开始\n");
gaem();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (z);
return 0;
}
5.1 限定猜数字的次数
其实原理和上面的计数是一样的,只需要在循环里面改变就可以了。
void gaem()
{
int guess = 0;
int z = 5;
int r = rand() % 100 + 1;
while (1)
{
printf("\n你还有%d次机会\n", z);
z--;
printf("猜数字:");
scanf("%d", &guess);
if (guess > r)
{
printf("猜大了\n");
}
else if (guess < r)
{
printf("猜小了\n");
}
else
{
printf("猜对了~~~\n");
break;
}
if (z == 0)
{
printf("你失败了,正确值是:%d\n", r);
}
}
}
6.分析猜数字小游戏原理
这个猜数字小游戏可以分成两个部分:1. 打印菜单 2. 循环体猜数字
接下来由作者将为大家详细讲解
6.1 打印菜单
首先这三个头文件得包含;
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
假设我们在玩一个游戏,玩完觉得不过瘾,还想再玩一把,如果这个游戏结束之后,需要关掉,重新打开,是不是就挺麻烦的?
那我们是不是可以这样想,就是运行玩完一把之后,不在退出程序,可以重新再来一把,比如说这把玩完了给你一个选择,选择 1 继续玩游戏,选择 0 就退出游戏。那这么一个逻辑,是不是提供一个菜单就可以实现?
那这个时候就可以给大家一个 do while 的循环结构
do while 循环的特点就是,上来之后不管三七二十一直接菜单
6.1.1 第一步:
方法1 :
int main ()
{
do
{
//直接在里面打印菜单的话,有点啰嗦,,那我们是不是可以直接分装一个函数来打印菜单
meun();
}while ();
return 0;
}
方法2:
int main ()
{
do
{
printf("**************************\n");
printf("****** 1. 开始游戏 ******\n");
printf("****** 0. 结束游戏 ******\n");
printf("**************************\n");
.....
}while ();
return 0;
}
这两种方法都正确,看大家按照喜好选择就可以;
6.1.2第二步:分装一个函数打印菜单
//那我们就可以在主函数的外面分装一个简易的菜单,他的类型我们就可以就可以写成“void”,
//“meun”的返回类型就是不需要他做任何返回,只需要悄悄地打印就可以了,因为前面我们写成了“void”,“void”的意思就是不需要返回;
void meun()
{
printf("**************************\n");//这里可以打印的菜单可以是多样化的,我这里只是给大家一个示范。
printf("****** 1. 开始游戏 ******\n");
printf("****** 0. 结束游戏 ******\n");
printf("**************************\n");
}
6.1.3第三步:判断是否继续
void meun()
{
printf("**************************\n");
printf("****** 1. 开始游戏 ******\n");
printf("****** 0. 结束游戏 ******\n");
printf("**************************\n");
}
int main ()
{
int z = 0;
do
{
meun();
//那菜单打印出来之后,我们是不是就可以判断了,是玩游戏还是退出游戏,那我们这里提示一下
printf("请选择:");
//那这里选了1或0,就是输入一个值嘛,那就需要一个整形变量零存储这个值,那就在循环外面定义一下
scanf("%d",&z);
//在这里有人选择了 1或0 ,但是也有可能不小心选择了其他的数
//那我们是不是就需要根据别人的选择做出相应的处理,那我们就可以使用上“switch”选择语句了
}while ();
return 0;
}
6.1.4 第四步 :使用“switch”语句
方法1 :
int main ()
{
int z = 0;
do
{
printf("**************************\n");
printf("****** 1. 开始游戏 ******\n");
printf("****** 0. 结束游戏 ******\n");
printf("**************************\n");
printf("请选择:");
scanf("%d",&z);
//使用 switch 语句判断 z 的值到底是什么
switch (z)
{
case 1:
printf("游戏开始\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
//当我们选择了 0 ,break 跳出来,就可以直接结束,那我们就可以在 “while” 里面放上“z”,
//刚好0为假嘛,whike 就直接结束循环,而选择错误为非0,继续循环重新选择。这里大家就可以自己去测试一下了
}while (z);
return 0;
}
方法2图片演示:
6.2 循环体猜数字
6.2.1 第一步:分装一个game函数
int main()
{
int z = 0;
do
{
meun();//菜单
printf("请选择 :>");
scanf("%d", &z);
switch (z)
{
case 1:
printf("游戏开始\n");
//开始游戏之后就可以直接从掉用我们分装的这个函数;
gaem();//猜数字
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (z);
return 0;
6.2.2 第二步:生成随机数
//首先函数类型,不需要它返回值,就可以写“void”,函数名字“gaen”
//这个里面就可以实现整个猜数字的过程
void gaem()
{
//用“gaen”生成随机数,使用 rand() % 100 + 1,然后在把他存在变量 r 里面去
//而调用“rand”之前,我们还调用 srand 而这个参数还得由 (time(NULL) 给我们产生的
//而这个 srand(time(NULL)) 这个返回值我们最好强制类型转换一下
//这里需要注意一点:还记得我们前面说过的srand函数是不需要频繁调用的
//⼀次运行的程序中调用⼀次就够了反倒是频繁调用会出问题的
//如果我们放在这个循环里面,就会每循环玩一次就会调用一次,那这个怎么解决呢?
//我们可以把它放进主函数里面去,就只需要在开始的时候调用一次就够了
int r = rand() % 100 + 1;
}
如:
int main()
{
int z = 0;
srand((unsigned int)time(NULL));
do
{
meun();
printf("请选择 :>");
scanf("%d", &z);
switch (z)
{
case 1:
printf("游戏开始\n");
gaem();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (z);
return 0;
}
6.2.3 第三步:猜数字
void gaem()
{
int guess = 0;
int r = rand() % 100 + 1;
//首先还是先提醒一下
printf("猜数字:");
//那猜数字是不是得猜,得输入一个数,那就需要定义一个变量,并且把它存起来
scanf("%d", &guess);
//然后开始判断:
if (guess > r)
{
printf("猜大了\n");//如果你猜的数大于 r 那就提示你猜大了
}
else if (guess < r)
{
printf("猜小了\n");//如果你猜的数小于 r 那就提示你猜小了
}
else
{
printf("猜对了~~~\n");//如果你猜的数等于 r 那就提示你猜对了
break;
}
}
但是如果猜大了或者猜小了,那是不是就得用循环来继续游戏,不然猜一次就结束了,循环我们就可以用 while 循环
void gaem()
{
int guess = 0;
int z = 5;
int r = rand() % 100 + 1;
while (1)//这个里面给上一个1,就够了,死循环一直猜,直到你猜对了 break 跳出去
{
printf("\n你还有%d次机会\n", z);
z--;
printf("猜数字:");
scanf("%d", &guess);
if (guess > r)
{
printf("猜大了\n");
}
else if (guess < r)
{
printf("猜小了\n");
}
else
{
printf("猜对了~~~\n");
break;
}
}
}
6.2.4 源码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void meun()
{
printf("**************************\n");
printf("****** 1. 开始游戏 ******\n");
printf("****** 0. 结束游戏 ******\n");
printf("**************************\n");
}
void gaem()
{
int guess = 0;
int r = rand() % 100 + 1;
while (1)
{
printf("猜数字:");
scanf("%d", &guess);
if (guess > r)
{
printf("猜大了\n");
}
else if (guess < r)
{
printf("猜小了\n");
}
else
{
printf("猜对了~~~\n");
break;
}
}
}
int main()
{
int z = 0;
srand((unsigned int)time(NULL));
do
{
meun();
printf("请选择 :>");
scanf("%d", &z);
switch (z)
{
case 1:
printf("游戏开始\n");
gaem();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (z);
return 0;
}