前言
在学习了选择和循环结构后,我们就可以根据现有的知识编写一些简单有趣的代码了。下面介绍一种简单又好玩的猜数字游戏,希望大家在游戏中体会到编程的快乐!
游戏简介
电脑自动生成1~100的随机数。玩家猜数字,如果猜大了,则提示“猜大了!”,如果猜小了,则提示“猜小了!”,如果猜对了,则提示“恭喜你,猜对了!”。
实现过程
一、打印菜单
为使main函数部分代码简洁,这里单独封装menu函数实现打印菜单功能。实现过程较简单,即玩家输入“1”,开始游戏;玩家输入“0”,退出游戏,这里不过多赘述。
void menu()
{
printf("*****************************\n");
printf("*****************************\n");
printf("***** 1.PLAY ******\n");
printf("***** 0.EXIT ******\n");
printf("*****************************\n");
printf("*****************************\n");
}
二、确定游戏框架
下面我们来确定游戏主体框架,即main函数部分。
为实现玩家输入“1”,开始游戏;玩家输入“0”,退出游戏;玩家输入其他数字,提示无效输入。考虑使用switch语句。
由于为保证玩家能进行多次游戏,且需要保证循环体至少执行一次,考虑使用do-while循环。
int main()
{
int input = 0;
do
{
menu();//打印菜单
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();//game函数部分请看后面哦!
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("无效选择!请重新选择!\n");
break;
}
} while (input);//input为1,能继续循环;input为0,退出游戏
return 0;
}
三、生成随机数
确定游戏框架后,怎么让计算机自动生成随机数呢?
为使计算机能自动生成随机数,下面我们先介绍几种函数,相信看完后你就能明白其中的秘密。
1、rand函数
C语言提供了一个函数叫rand,这个函数是可以生成随机数的。使用时需包含头文件<stdlib.h>。
函数原型:
int rand (void);
rand函数会返回一个(伪)随机数,这个随机数的范围实在0~RAND_MAX之间,RAND_MAX的大小是依赖编译器实现的,但是大部分编译器上RAND_MAX是32767。
下面我们就测试一下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个随机数:
可是,我们发现,不管程序运行几次,生成的随机数总是这5个:
生成的随机数“不随机”,这是为什么呢?
原来,rand函数生成的随机数是伪随机的,伪随机数不是真正的随机数,是通过某种算法生成的随机数。rand函数是对一个叫做“种子”的基准值进行运算而生成的随机数。
之所以前面每次运行程序产生的随机数是一样的,是因为rand函数默认生成随机数的种子为1。
那么,为了生成不同的随机数,就要让rand函数的“种子”是变化的。
2、srand函数
C语言中又提供了一个函数叫srand,这个函数是用来初始化随机数的生成器的。使用时需包含头文件<stdlib.h>。
函数原型:
void srand (unsigned int seed);
所以,程序中在调用rand函数之前,要先调用srand函数,通过srand函数的参数seed来初始化rand函数生成随机数时的种子。这样,种子在变化,每次生成的随机数也就是变化的。
也就是说,如果给srand函数的种子如果是随机的,rand就能生成随机数。
那么,怎样使srand函数的种子是随机的呢?
3、time函数
在程序中,我们一般是使用程序运行的时间作为种子的,因为时间是时刻在发生变化的。
C语言中提供了一个函数叫time,这个函数可以用来获取时间。使用时需包含头文件<time.h>。
函数原型:
time_t time (timr_t* timer);
time函数会返回当前的日历时间,实际上,time函数返回的是1970年1月1日0时0分0秒到现在程序运行时间的差值,单位是秒。返回的类型是time_t类型的,time_t类型本质上其实是32(#`O′)或64位的整形类型。
如果time函数的参数timer是空指针NULL,就只会返回这个时间的差值,返回的这个时间差也叫:时间戳。
即如果只是想让time函数返回时间戳,我们就可以这样写:
time (NULL);
学习了rand srand time这三种函数后,我们就可以将生成随机数的代码改写如下:
注意:由于time函数的返回值是整形,而srand函数的参数是unsigned int,这里需要将time函数的返回值强制类型转换 。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand((unsigned int)time(NULL));//使用time函数的返回值设置种子
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
return 0;
}
这样,我们就可以每次都真正产生完全随机的5个数:
4、设置随机数的范围
由于我们只需要产生0~100之间的随机数,而rand函数最大能产生的随机数为32767,这对我们来说太大了,这就需要设置随机数的范围。
这里需要一点数学知识,我们要知道,任何一个数除以100的余数一定是在0到99之间的,那么如果要生成1到100之间的随机数,方法如下:
rand () % 100 + 1;//这时余数范围为1~100
以此类推,如果要生成100~200之间的随机数,方法如下:
100 + rand () % (200 - 100 + 1)//余数的范围是0~100,加100后就是100~200
如果要生成a~b之间的随机数,方法如下:
a + rand () % (b - a + 1);
三、实现猜数字
最后,我们来到游戏的game函数部分。
我们通过无限循环while(1)来实现反复输入所猜的数字,并反复给出提示与反馈。
首先确定1~100之间的一个随机数,然后玩家输入一个数字,如果猜大了,则提示“猜大了!”,如果猜小了,则提示“猜小了!”,如果猜对了,则提示“恭喜你,猜对了!”。
void game()
{
int ret = rand()%100+1;
int guess = 0;
while (1)
{
printf("请猜数字:");
scanf("%d", &guess);
if (guess < ret)
{
printf("猜小了!\n");
}
else if (guess > ret)
{
printf("猜大了!\n");
}
else
{
printf("恭喜你,猜对了!\n");
break;
}
}
}
完整源码
能看到这里,你实在太棒了!
好了!下面让我们一起来看一看完整的C语言源代码吧!
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("*****************************\n");
printf("*****************************\n");
printf("***** 1.PLAY ******\n");
printf("***** 0.EXIT ******\n");
printf("*****************************\n");
printf("*****************************\n");
}
void game()
{
int ret = rand()%100+1;
int guess = 0;
while (1)
{
printf("请猜数字:");
scanf("%d", &guess);
if (guess < ret)
{
printf("猜小了!\n");
}
else if (guess > ret)
{
printf("猜大了!\n");
}
else//guess=ret,猜对了!
{
printf("恭喜你,猜对了!\n");
break;
}
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//设置种子,在调用rand函数之前先调用srand函数
do
{
menu();//打印菜单
printf("请选择:");
scanf("%d", &input);//输入所猜的数字
switch (input)
{
case 1:
game();//进入游戏game函数部分
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("无效选择!请重新选择!\n");
break;
}
} while (input);
return 0;
}
这里有一点需要重点说明,就是srand函数调用的位置。即do-while循环之外,主函数之中。由于种子只需要设置一次即可,所以srand函数一定要在main函数之中,因为main函数只执行一次,而不能在game函数之中。如果将srand函数放在game中,则会导致两次游戏生成的随机数非常相近。且一定要在do-while循环之外,否则每次猜一个数字后电脑生成的随机数都会改变,导致游戏出现bug。
游戏机制优化——次数限制
为了增加游戏的趣味性,让游戏变得更加刺激,我们还可以加上次数限制。玩家有5次猜数字机会,如果5次猜不出来,则游戏失败。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("*****************************\n");
printf("*****************************\n");
printf("***** 1.PLAY ******\n");
printf("***** 0.EXIT ******\n");
printf("*****************************\n");
printf("*****************************\n");
}
void game()
{
int ret = rand()%100+1;
int guess = 0;
int count = 5;//引入计数变量count
while (1)
{
printf("请猜数字:");
scanf("%d", &guess);
if (guess < ret)
{
printf("猜小了!\n");
}
else if (guess > ret)
{
printf("猜大了!\n");
}
else
{
printf("恭喜你,猜对了!\n");
break;
}
count--;//每次猜错count--
if (count == 0)
{
printf("失败了!正确的数字是:%d\n", ret);//失败了,显示正确数字
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("游戏结束\n");
break;
default:
printf("无效选择!请重新选择!\n");
break;
}
} while (input);
return 0;
}
总结
今天我们学习了选择与循环结构的简单应用,实现了简单又好玩的猜数字游戏。快去和你的小伙伴们玩起来吧!