前言
想玩一个数字范围在1~100的猜数字游戏,根据自己浅薄的知识怎样把这个游戏写出来呢?
一个简单的猜数字游戏是怎样构思又怎样逐步实现的呢?接下来请允许我为大家详细介绍一下吧!
1.大致思路
想要实现一个猜数字游戏,说简单点,最核心的部分就是先让电脑生成一个随机数,然后再让玩家输入值猜这个随机数,程序再根据玩家输入的值与这个随机数进行比较,接着再反馈给玩家一定的提示,最终使其猜出正确的数字。
2.猜数字游戏的核心部分(生成随机数)
2.1函数
想要实现以上随机数的生成,我们必须要知道C语言中的函数。
2.1.1什么是函数?(初识C语言函数的概念)
在数学中,我们已经知道函数的概念,简单点,假如题目中给了我们一个y=2x-1的函数,当我想知道y的值时,有了这个函数,我只需知道x的值就能得出y的值。
C语言中的函数与数学中的函数大致相似,都是由一份数据经过一定的计算或规则得到另一份数据,为什么说大致相似,是因为它们确实又有着天壤之别。
‘函数’的英文为function,可是function翻译成中文又有‘功能’的意思,在C语言中,把function翻译为‘功能’或许更恰当。我们知道,一个程序的实现由多个函数组成,每一个函数负责实现一定的功能,一个程序由多个函数组成,也就是说:一个程序的实现由多个小的功能叠加而实现!
2.1.2C语言函数的定义
在C语言中,函数有以下4个组成部分:
先例举一个add函数:
①返回类型:一个函数可以返回一个值。
上图中我们计算的是两个数的和,需要返回整数,所以int是函数返回的值的数据类型。有些函数在执行完毕后不需要返回值,在这种情况下,返回类型就用关键字 void(空类型);
②函数名称:这是函数的实际名称。如上图的‘Add’,函数名可以由我们直接来命名;
③参数:参数就像是占位符。当函数被调用时,向参数传递一个值,比如上图中我们传递给Add函数一个x和y的值,x和y就是我们的参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
④函数体:函数主体包含一组定义函数执行任务的语句。
2.1.3 函数的分类(以随机数的生成为例)
函数分为库函数和自定义函数。
那么库函数和自定义函数又是什么呢?本文以猜数字游戏的实现为基础,首先讲解库函数的概念,再自然而然就会引出自定义函数。
库函数
在初识C语言1中我们就已经提到过printf函数和scanf函数,这两个函数就是库函数,库函数就是由C语言为我们提供的现成的函数,可以直接使用。事实上,为了我们在编写程序时提高效率,C语言在发布时就为我们封装好了许多函数,这些函数就是库函数。
引到本文主题,比如在猜数字游戏中想要生成一个随机数,怎么来实现呢?这就需要用到一个库函数rand了,登录网站https://cplusplus.com我们查询一下rand函数的用法,如下图所示:
(https://cplusplus.com网站查找库函数使用方法:在首页点击右上角Legacy version切换到旧版本,在搜索框中输入函数名称查找)
接下来我们用一下rand函数生成随机数看一下:
#include <stdio.h> #include <stdlib.h>//函数rand的头文件为stdlib.h int main() { int input = 1; while (input) { scanf("%d", &input); printf("%d\n", rand()); } return 0; }
第一次运行结果:
第二次运行结果:
不难发现,我们每次程序运行生成的随机数都如出一辙,这要是玩猜数字游戏,我记住了第一次程序运行的数据,后面再玩我都知道了随机数是什么,那这游戏玩的还有什么意思呢?
那问题出在哪里了呢?怎么才能保证我每次程序运行的结果都不一样呢?我们再返回去看一下rand函数的用法:
可见在使用rand函数时,我们必须先引用srand函数对rand初始化:所以我们再在此基础上引用一下srand函数:
观察以上两个图,这时候又有问题了:每次生成的随机数好像也并不随机呀!我只有每次给srand函数传递一个不同的参数(就是上图中括号中的1与2),程序才能每次生成不同的随机数,那我想达到目的还要每次给你传递一个不同的参数吗?
可是这就很矛盾了啊,我用这个函数就是为了生成随机数的,你还要我给你传递一个随机数,那我干脆自己生成随机数好了,还要你这个函数干嘛呢?
这是为什么呢?我们函数用错了吗?方法不对吗?
其实不是的,我们的思路没有问题,函数也没有用错,我们的问题已经解决一大半了:想正常生成随机数,无非就是随机传递给srand函数一个参数罢了,那又怎么随机给srand函数传参呢?
时光如剑,日月如梭!我们在思考问题,感叹人生时,时间都在一分一秒的过去,哎呀!我们的时间一直都在变化呀!那么我们能不能把时间作为参数传递给srand呢?答案当然是可以的!
我们再打开网站https://cplusplus.com查询一下time函数:
什么是时间戳?见下图:
这时候我们再重新整合生成随机数的代码:
#include <stdio.h> #include <stdlib.h>//函数rand的头文件为stdlib.h #include <time.h>//函数time的头文件为time.h int main() { int input = 1; srand((unsigned)time(NULL)); //srand函数所需参数是unsigned int(无符号整型)类型 //time函数的返回类型为time_t类型,其实质也是整型; //所以time函数的返回值自然而然可以用于srand函数的参数; //在上图中我们知道time函数不使用参数仍可以返回我们想要的值。 //故time函数的参数我们用NULL(空指针),NULL以后会再提到,此处不再深究。 while (input) { scanf("%d", &input); int random_num = rand() % 100 + 1;//任意数模100,余数为0~99,再加1,余数为1~100// printf("%d\n", random_num); } return 0; }
以上才是正确生成随机数的方法。
生成随机数的问题我们解决了,接着玩游戏,我猜数字一下子猜不对,程序总要给我反馈帮助我猜出正确答案吧,所以游戏主体部分我们可以这样写:
#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { int input = 1; int random_num = rand() % 100 + 1; //注意要把此等式放在循环外部,否则我们猜一次随机数就会变一次, //永远无法根据程序的反馈信息猜出正确答案! srand((unsigned)time(NULL)); printf("请输入你猜的数字:\n"); while (1) { scanf("%d", &input); if (input > random_num) { printf("猜大了,请再输入一次:\n"); } else if (input < random_num) { printf("猜小了,请再输入一次:\n"); } else { printf("恭喜你,猜对了!\n"); break; } } return 0; }
结果展示:
2.开始菜单
一个稍微上档次一些的游戏当然要有开始菜单吧,想玩就进入游戏,不想玩就直接退出。
我们就可以这样想:想玩你就输入1,程序就继续进行;不想玩你就输入0,直接退出游戏。
所以开始菜单代码我们想这样展示:
printf("这是一个猜数字游戏,数字范围是1~100\n"); printf("******如果你想玩,请输入数字1******\n"); printf("如果你不想玩,请输入数字0,退出游戏\n");
接下来玩家的选择代码我们就可以用switch语句来写:
int input = 0; scanf("%d", &input); switch (input) { case 1: printf("游戏开始,请输入数字:\n"); case 0: printf("退出游戏\n"); default: printf("选择错误,请重新选择:\n"); }
可是我们玩完一把后还想接着玩,怎么办呢?这时就可以在此基础上加上循环语句,观察以上代码,显然用do...while循环语句最合适,就可以接着这样写:
int input = 0; do { scanf("%d", &input); switch (input) { case 1: printf("游戏开始,请输入数字:\n"); break; case 0: printf("退出游戏\n"); break; default: printf("选择错误,请重新选择:\n"); break; } } while (input); //当输入input≠0时,结果为真,打印完对应语句继续进入循环,程序继续运行; //当输入input=0时,结果为假,打印完“退出游戏”直接退出循环,程序终止运行; //开始菜单那里为什么用1和0,最重要的用处也体现在这里了
自定义函数
上面提到了库函数的查询,那么什么是自定义函数呢?
顾名思义,自定义函数当然是我们自己来设计的函数,自定义函数和库函数一样,有函数名,返回值类型和函数参数。
当我们写一个程序需要频繁的使用一个功能,或者为了实现一个功能需要写的代码量太多了,我们不希望主函数中的代码看起来繁琐杂乱无章,这时候我们完全可以把这段代码分装成函数,每次用到这个功能时只需调用函数即可。
比如以上的生成随机数和开始菜单我们就可以分装成game函数和menu函数:
完整代码:
#include <stdio.h> #include <stdlib.h> #include <time.h> void menu() { printf("这是一个猜数字游戏,数字范围是1~100\n"); printf("******如果你想玩,请输入数字1******\n"); printf("如果你不想玩,请输入数字0,退出游戏\n"); } void game() { int random_num = rand() % 100 + 1; int input = 0; while (1) { scanf("%d", &input); if (input > random_num) { printf("猜大了,请再输入一次:\n"); } else if (input < random_num) { printf("猜小了,请再输入一次:\n"); } else { printf("恭喜你,猜对了!\n"); break; } } } int main() { int input = 0; srand((unsigned)time(NULL)); //把此句写在主函数里是为了一次程序运行只调用一次time函数, //无需一直给srand传参 do { menu();//函数的调用:调用menu函数。 scanf("%d", &input); switch (input) { case 1: printf("游戏开始,请输入数字:\n"); game();//调用game函数。 break; case 0: printf("退出游戏\n"); break; default: printf("选择错误,请重新选择:\n"); break; } } while (input); return 0; }
最后
函数的知识还有很多,比如函数的递归与迭代,传值调用和传址调用,本文中的猜数字游戏没有用到,先不提。后续再总结。