【手把手教你实现C语言】猜数字游戏
一、前言: 什么是猜数字游戏 ?
写⼀个猜数字游戏
游戏要求:
- 电脑随机⽣成1~100的随机数
- 玩家猜数字
如果猜小了,电脑提示猜小了;
如果猜大了,电脑提示猜大了;
如果猜对了,电脑提示:恭喜你,猜对了,游戏结束 - 如果玩完一次游戏后,不过瘾的话,还可以继续玩
二、 游戏实现思路
1. 打开方式
一般玩游戏的时候,一般如下图所示的界面,只要点击界面上的按钮,就可以实现开始游戏的效果。我们把这个界面就叫做 “菜单”。
2. 实现逻辑
那么我们在打开“开始游戏”界面后,就进入了游戏,那么游戏的实现逻辑就如前言给出的要求一样 。
首先电脑先给出一个1-100的随机数,能够让玩家去猜测。
在系统确定了一个数字之后,玩家就开始猜数字,这时候我们可以用一个整型变量来保存玩家输入的数字,然后告诉玩家是猜大了还是猜小了,还是猜中了。
如果猜中了,则游戏结束;如果猜错了,则让玩家继续猜,直到猜中为止。
游戏结束后,通常又会跳出一个界面,是继续玩游戏呢?还是退出游戏呢?这时可以把最开始的菜单调出来,让玩家再次选择,是否再次进入游戏。
当然,在游戏结束前,我们还可以把每一局游戏玩家猜的次数告诉玩家。
以上就是一个完整的猜数字游戏的思路了,重点总结如下:
(1)菜单
(2)生成随机数
(3)猜数字循环
三、代码实现
1. 随机数
1.1 rand函数
随机数的生成可以使用C语言库函数中的rand函数【1】。
rand函数原型为:int rand (void);
(void指的是rand函数不需要参数,但调用rand函数就会返回一个int类型的随机数。)
rand函数会返回一个伪随机数。这个随机数的范围是在0~RAND_MAX之间,这个RAND_MAX的大小是依赖编译器上实现的,但是⼤部分编译器上是32767。
rand函数的使⽤需要包含⼀个头⽂件是:stdlib.h,即
#include <stdlib.h>
接下来,测试一下rand函数,调⽤5次rand函数,产⽣5个随机数。
#include <stdio.h>
#include <stdlib.h>//rand函数的使用需要包含头文件:stdlib.h
int main()
{
//rand函数生成随机数的默认种子是1
int r = rand();//生成的随机数为r,rand()是调用rand函数不需要传参
printf("%d\n", r);
r = rand();
printf("%d\n", r);
r = rand();
printf("%d\n", r);
r = rand();
printf("%d\n", r);
return 0;
}
调试程序后,发现无论测试多少次,5个随机数的值不变(玩完一次游戏后,第二次的值与第一次的值相同),就说明使用rand函数不能生成我们想要的随机数。
最后发现:
(1)rand函数⽣成的随机数是伪随机数,不是真正的随机数,是通过某种算法⽣成的随机数。真正的随机数的是⽆法预测下⼀个值是多少的。
(2)⽽rand函数是对⼀个叫“种⼦”的基准值进⾏运算⽣成的随机数。之所以前⾯每次运⾏程序产⽣的随机数序列是⼀样的,那是因为rand函数⽣成随机数的默认种⼦是1。
(3)如果要⽣成不同的随机数,就要让种⼦是变化的。
1.2 srand函数
C语言提供了srand函数【2】,用来初始化随机数的生成器(改变默认种子的值)。
srand函数的原型为:void srand (unsigned int seed);
(srand函数传入的参数类型为unsigned int,返回值为void 空值 )
#include <stdio.h>
#include <stdlib.h>//rand函数的使用需要包含头文件:stdlib.h
int main()
{
srand(2);//srand函数设置随机种子为2
//rand函数生成随机数的默认种子是1
int r = rand();//生成的随机数为r,rand()是调用rand函数不需要传参
printf("%d\n", r);
r = rand();
printf("%d\n", r);
r = rand();
printf("%d\n", r);
r = rand();
printf("%d\n", r);
return 0;
}
(1)srand函数设置随机种子的值为2,发现生成的随机数较rand函数生成的随机数有变化,但是多次执行后,发现随机数的值还是没有变化。
(2)原因在于:srand函数设置的随机种子是固定值2。所以我们需要一个随机值来作为srand的种子,但生成随机数的时候又需要一个随机数,互相矛盾。
1.3 time函数
- 我们想到可以用程序运⾏的时间作为种⼦的,因为时间时刻在发⽣变化的。
在C语言提供了time函数【3】,就可以获得这个时间,time函数原型如下:time_t time (time_t* timer);
(1)time 函数会返回当前的⽇历时间,其实返回的是1970年1⽉1⽇0时0分0秒到现在程序运⾏时间之间的
差值,单位是秒。返回的类型是time_t类型的,time_t 类型本质上其实就是32位或者64位的整型类型。
(2)time函数的参数 timer 如果是⾮NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。
(3)如果 timer 是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。
(4)time函数的时候需要包含头⽂件:time.h
我们可以利用时间戳【4】(时间戳:timer 是NULL,就只返回这个时间的差值,time函数返回的时间差)生成随机数。
- 那么如何使用时间戳生成随机数呢?
参照 cplusplus网站rand函数的例子 ,只是让time函数返回时间戳:time(NULL)
//调⽤time函数返回时间戳,这⾥没有接收返回值
- 利用rand函数、srand函数和time函数(时间戳)生成随机数
#include <stdio.h>
#include <stdlib.h>//rand、srand函数的使用需要包含头文件:stdlib.h
#include <time.h> //time函数的使用需要包含头文件:time.h
int main()
{
//使用time函数的返回值设置种子
//因为srand的参数是unsigned int类型,我们将time函数的返回值强制类型转换
srand((unsigned int) time(NULL));
int r = rand();//生成的随机数为r,rand()是调用rand函数不需要传参
printf("%d\n", r);
r = rand();
printf("%d\n", r);
r = rand();
printf("%d\n", r);
r = rand();
printf("%d\n", r);
return 0;
}
多运行几次,发现产生的随机数都不同。
- 产生1~100之间的随机数(参考 cplusplus网站rand函数的例子 )
(1)生成1-100之间的随机数:rand()%100+1; (%100的余数是0-99,0-99的数字+1,范围是1~100)
(2)生成a~b的随机数: a + rand()%(b-a+1)
(3)生成随机数之前需要调用srand来设置随机数的生成起点,srand函数只需要调⽤⼀次就够了,不能频繁调用。
#include <stdio.h>
#include <stdlib.h>//rand函数的使用需要包含头文件:stdlib.h
#include <time.h> //time函数的使用需要包含头文件:time.h
int main()
{
//使用time函数的返回值设置种子
//因为srand的参数是unsigned int类型,我们将time函数的返回值强制类型转换
srand((unsigned int) time(NULL));
int r = rand()% 100 + 1;//生成a~b的随机数: a + rand()%(b-a+1)
printf("%d\n", r);
r = rand() % 100 + 1;;
printf("%d\n", r);
r = rand() % 100 + 1;;
printf("%d\n", r);
r = rand() % 100 + 1;;
printf("%d\n", r);
return 0;
}
2. 游戏菜单
游戏一开始,就有一个菜单出现(do…菜单…while),供玩家选择玩游戏还是不玩游戏。
#include <stdio.h>
int main()
{
int input = 0;//初始化input为玩家的选择: 1:play; 0:exit
do//do..while语句:游戏开始就出现菜单
{
printf("******************\n");
printf("***** 1.play *****\n");
printf("***** 0.exit *****\n");
printf("******************\n");
printf(" 请选择:");//定义进入游戏的菜单
scanf("%d", &input);//键盘输出1或者0,接收玩家的选择
switch (input)//switch语句,创建分支:根据玩家的选择判断是否进行游戏
{
case 1:
printf("猜数字\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);//当玩家选择完成后,while判断输入可以继续供玩家选择玩游戏与否
return 0;
}
当然也可以将菜单封装到menu()
函数中,使代码更简洁。
封装的menu()
函数:
封装函数和运行效果如下:
#include <stdio.h>
void menu()
{
printf("******************\n");
printf("***** 1.play *****\n");
printf("***** 0.exit *****\n");
printf("******************\n");
}
int main()
{
int input = 0;//初始化input为玩家的选择: 1:play; 0:exit
do//do..while语句:游戏开始就出现菜单
{
menu();//调用函数
printf(" 请选择:");//定义进入游戏的菜单
scanf("%d", &input);//键盘输出1或者0,接收玩家的选择
switch (input)//switch语句,创建分支:根据玩家的选择判断是否进行游戏
{
case 1:
printf("猜数字\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);//当玩家选择完成后,while判断输入可以继续供玩家选择玩游戏与否
return 0;
}
3. 猜数字循环
同样的,猜数字游戏也可以封装成一个函数game();
game();
函数:
四、 整体代码
1.按照前言要求实现的代码和运行效果如下
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("******************\n");
printf("***** 1.play *****\n");
printf("***** 0.exit *****\n");
printf("******************\n");
}
void game()
{
//1.生成随机数
//srand((unsigned int)time(NULL));//生成随机数之前需要调用srand来设置随机数的生成起点,
//srand函数只需要调用一次就够了,不能频繁调用。
int r = rand() % 100 + 1;
//2.猜数字
int guess = 0;
while (1)
{
printf("请猜数字:");
scanf("%d", &guess);
if (guess < r)
printf("猜小了\n");
else if (guess > r)
printf("猜大了\n");
else
{
printf("恭喜你,猜对了,随机数是:%d\n",r);
break;
}
}
}
int main()
{
int input = 0;//初始化input为玩家的选择: 1:play; 0:exit
srand((unsigned int)time(NULL));//因为生成随机数之前需要调用srand来设置随机数的生成起点,
//srand函数只需要调用一次就够了,不能频繁调用。
//所以srand函数没有写在game()函数中,而是写在主函数中,只调用一次就行。
do//do..while语句:游戏开始就出现菜单
{
menu();//调用函数
printf("请选择:");//定义进入游戏的菜单
scanf("%d", &input);//键盘输出1或者0,接收玩家的选择
switch (input)//switch语句,创建分支:根据玩家的选择判断是否进行游戏
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);//当玩家选择完成后,while判断输入可以继续供玩家选择玩游戏与否
return 0;
}
2. 如果在1的基础上,加上玩家最多猜测5次的要求
可以在game()函数中的while循环中加入一个计数变量等于5,当计数变量为0后,直接打印猜数字游戏失败。
最终代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("******************\n");
printf("***** 1.play *****\n");
printf("***** 0.exit *****\n");
printf("******************\n");
}
void game()
{
//1.生成随机数
//srand((unsigned int)time(NULL));//生成随机数之前需要调用srand来设置随机数的生成起点,
//srand函数只需要调用一次就够了,不能频繁调用。
int r = rand() % 100 + 1;
//2.猜数字
int guess = 0;
int count = 5;
while (count)
{
printf("你还有%d次机会\n", count);
printf("请猜数字(1~100):");
scanf("%d", &guess);
if (guess < r)
printf("猜小了\n");
else if (guess > r)
printf("猜大了\n");
else
{
printf("恭喜你,猜对了,随机数是:%d\n", r);
break;
}
count--;
}
if (count == 0)
{
printf("你失败了,随机数是%d\n", r);
}
}
int main()
{
int input = 0;//初始化input为玩家的选择: 1:play; 0:exit
srand((unsigned int)time(NULL));//因为生成随机数之前需要调用srand来设置随机数的生成起点,
//srand函数只需要调用一次就够了,不能频繁调用。
//所以srand函数没有写在game()函数中,而是写在主函数中,只调用一次就行。
do//do..while语句:游戏开始就出现菜单
{
menu();//调用函数
printf("请选择:");//定义进入游戏的菜单
scanf("%d", &input);//键盘输出1或者0,接收玩家的选择
switch (input)//switch语句,创建分支:根据玩家的选择判断是否进行游戏
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);//当玩家选择完成后,while判断输入可以继续供玩家选择玩游戏与否
return 0;
}