一、猜数字游戏
游戏要求:
1.要求电脑生成1~100的随机数;
2.玩家猜数字,在猜数字的过程中,根据所猜测出的结果程序会给出猜大了或猜小了的反馈,直到你的猜测结果正确,游戏结束。
乍一看,是不是感觉挺简单的啊,不就是猜数字吗?这我还能不会吗?但当你冷静下来仔细看一下我们的大标题“C语言”,是不是有点慌了。
不过不要怕,且听我娓娓道来。
那么这其中让我们觉得有点困难的地方在哪呢?我们再仔细审题,“随机数...."emm...,我寻思着我也不会生成随机数啊?你看,这病源不就找到了吗?既然找到了病源,那俺就好下药了。
接下来,我会将该游戏实现前的所有准备工作向大家汇报:
1.rand
随机数的生成需要rand函数(头文件:stdlib.h)的应用,这个函数是可以生成随机数的,函数原型如下:
1 int rand (void);
rand函数会返回一个伪随机数(通过算法生成的,并非自然界真正的随机数),这个随机数的范围是0-RAND_MAX之间,这个RAND_MAX是依赖编译器上实现的,大部分编译器上是32767。
接下来我们来验证一下我们的初始代码:
第一次:
第二次:
王德法?这对吗?我们不是要生成随机数吗?第一次看着确实有那么点随机的味道,可这第二次是啥子哦。不信邪的我接连试了好几次,可还是这个结果,可想而知我当时的内心:
。待我冷静下来上网搜索了一番,结合前面对于rand函数的概念了解一番,还是被我发现了端倪:rand函数实际上是对一个叫“种子”的基准值进行运算生成的随机数。
那么我们的错因显而易见了:我们自认为完美无瑕的运行了不知道多少次,可结果无动于衷的罪魁祸首就是生成随机数的默认种子一直都是1!所以如果我们想要生成不同的随机数,就需要让种子是变化的。俺特地去C++rederence里调取了rand函数如下图:
在我的细心观察下,发现了一个名为srand的东东,后来一经搜索才发现这个东东大有用处。
2.srand
srand函数是用来初始化随机数的生成器(种子)的,函数原型如下:
1 void srand(unsigned int seed);
只要给srand传一个变化的值,rand就能生成随机数。我就说这俩咋长得这么像,这不就是兄弟之间的关系吗?哥哥(rand)吩咐弟弟(srand)事情,弟弟(srand)照做。个人认为这样好记二者之间的关系:srand中的s可以理解为small。但是仅有这俩兄弟是远远不够的。我们如何才能找到一个合适(变化)的“种子”呢?接下来有请我们日常生活中一直不怎么起眼的time“嘉宾”登场。
3.time(头文件:time.h)
在程序中我们一般是使用程序运行的时间作为种子,因为时间是时刻在发生变化的。
time函数原型如下:
time_t time(time_t* timer)
这里涉及到后面需要学习的指针,time_t*即为该函数原型中的指针,目前学识有限的我也不知道咋解释,就不管它了,撂倒一边去。这个参数我们就不用它了,直接传NULL。
time函数可以返回当前的日期时间。该返回值就是用现在程序运行的时间减去计算机的起始时间(1970.1.1 0:0:0),单位是秒。返回的类型是time_t类型,本质上其实就是32位或者64位的整型类型。
既然兄弟俩和我们的嘉宾都已经就绪,应该就可以为我们表演变脸(随机值)了吧。
第一次:
第二次:
接连好几次尝试,都是不一样的结果。
那么表演也是非常成功啊。当然在这里我们也要强调一下,如下图:
前面提到srand需要的参数类型是unsigned int,我们怕编译器不认识,所以我们将返回值转换成unsigned int。
已经到这一步了,可如果数字这么凌乱和不规则我们还猜啥数嘞,我们再回顾一下游戏要求:要求电脑生成1~100的随机数,那么我们肯定要设置随机数的范围。所以接下来我们来介绍一下随机数的生成方法。
4.设置随机数的范围:
如果要生成0~99之间的随机数:
rand () %100; //余数范围是0~99
如果要生成1~100之间的随机数:这个在上面的加1就行了
rand () %100 +1; //余数范围是1~100
如果要生成100~200之间的随机数:
100 + rand ()% (200-100+1)//余数的范围是0~100,加100后是100~200
所以我们可以得到一般情况:生成a~b的随机数:
a + rand ()% (b-a+1)
好啦,掌握以上知识就足够啦,我们可以来实现我们的猜数字游戏喽!
猜数字游戏的实现:初始版==>进阶版==>进阶版plus
初始版:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int i = 0;
do
{
printf("***************************\n");
printf("********* 1.play **********\n");
printf("********* 0.exit **********\n");
printf("***************************\n");
printf("请准备开始游戏,输入你的数字:");
scanf("%d", &i);
switch (i)
{
case 1:
printf("猜数字\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("别乱选,就俩数,一边玩去\n");
break;
}
} while (i);
return 0;
}
运行结果如下:
注:switch语句中的break跳出break只会跳出switch,不会跳出do while
通过观察我们不难发现,每次将那么长的菜单打印出来既不美观又繁琐,所以我们有什么方法可以将其单独封装吗?有的,兄弟,有的。
我们需要引入menu函数来封装:
void menu()
{
printf("***************************\n");
printf("********* 1.play **********\n");
printf("********* 0.exit **********\n");
printf("***************************\n");
}
完整代码:
void menu()
{
printf("***************************\n");
printf("********* 1.play **********\n");
printf("********* 0.exit **********\n");
printf("***************************\n");
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int i = 0;
srand((unsigned int) time(NULL));//由前面内容可知,此处应放入主函数,保证调用一次就行,没必要放入game函数
do
{
menu();
printf("请准备开始游戏,输入你的数字:");
scanf("%d", &i);
switch (i)
{
case 1:
printf("猜数字\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("别乱选,就俩数,一边玩去\n");
break;
}
} while (i);
return 0;
}
我们再来看看效果:
我们发现效果是一样的,但整体上美观多了。但我们再来看这串代码,总不能花费这么长时间写了个这么无聊的甚至称不上游戏的游戏吧。那当然是不可能的,心急吃不了热豆腐,且听我娓娓道来。
可是既然要优化我们的猜数字游戏,那么多的游戏内容如果放入我们的代码中会显得非常冗长,那么我们应该怎么办呢?相信你已经有了答案,没错,再找一个函数来封装我们的游戏内容。我们可以将case 1中的"printf("猜数字\n")"改为game()。于是有了以下进阶版代码:
void menu()
{
printf("***************************\n");
printf("********* 1.play **********\n");
printf("********* 0.exit **********\n");
printf("***************************\n");
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void game()
{
int r = rand() % 100 + 1;//生成随机数
int j = 0;//准备猜数字,可你知道你需要猜多少次才能猜对吗?并不知道,所以引入下面的while循环
while (1)
{
printf("请准备开始游戏,输入你的数字:");
scanf("%d", &j);
if (j < r)
printf("牢弟,猜小了,还得练\n");
else if (j > r)
{
printf("牢弟,猜大了,还得练\n");
}
else
{
printf("不错哦,猜对了,数字是:%d\n", r);
break;//因为这里是while的死循环
}
}
}
int main()
{
int i = 0;
srand((unsigned int)time(NULL));//由前面的内容可知,此处应该放入主函数,保证调用一次就行,没必要放入game函数
do
{
menu();
printf("请准备开始游戏,输入你的数字:");
scanf("%d", &i);
switch (i)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("别乱选,就俩数,一边玩去\n");
break;
}
} while (i);
return 0;
}
运行结果如下:
当然这里俺(古希腊掌管猜数字游戏的神)也是非常厉害,不到三次就猜出来了。说到次数,我们还可以将代码进一步优化得到进阶版plus,代码如下:
void menu()
{
printf("***************************\n");
printf("********* 1.play **********\n");
printf("********* 0.exit **********\n");
printf("***************************\n");
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void game()
{
int r = rand() % 100 + 1;//生成随机数
int j = 0;//准备猜数字,可你知道你需要猜多少次才能猜对吗?并不知道,所以引入下面的while循环
int count = 3;
while (count)
{
printf("还剩%d次机会\n", count);
printf("请准备开始游戏,输入你的数字:");
scanf("%d", &j);
if (j < r)
printf("牢弟,猜小了,还得练\n");
else if (j > r)
{
printf("牢弟,猜大了,还得练\n");
}
else
{
printf("不错哦,猜对了,数字是:%d\n", r);
break;//因为这里是while的死循环
}
count--;
}
if (count == 0)
printf("牢弟,次数没了,回家练吧\n");
}
int main()
{
int i = 0;
srand((unsigned int)time(NULL));//由前面的内容可知,此处应该放入主函数,保证调用一次就行,没必要放入game函数
do
{
menu();
printf("请准备开始游戏,输入你的数字:");
scanf("%d", &i);
switch (i)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("别乱选,就俩数,一边玩去\n");
break;
}
} while (i);
return 0;
}
代码运行如下:
忙到现在还没吃饭,没力气了,不然肯定出来了。
注:如果你想把这个程序拷贝给你的损友耍,记得将Debug改为Release就可以了。
二、关机程序
程序介绍:程序运行起来后,电脑就倒计时1分钟关机,如果在1分钟内输入“我是猪,我是猪,我是一只可爱的粉红pig”,就取消关机,不输入的话,1分钟就关机。
制作该程序提前需要了解:
shutdown:用来关机的命令
-s:设置关机
-t:设置倒计时
-a:取消关机
system 函数:用来执行命令的 strcmp函数:用来字符串的比较
所需头文件:<stdlib.h> 所需头文件:<string.h>
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char i[20] = { 0 };//字符数组,用来存放字符串
system("shutdown -s -t 60");
next:
printf("如果在1分钟内输入“我是猪,我是猪,我是一只可爱的粉红pig”就取消关机\n");
scanf("%s", &i);
if (strcmp(i, "我是猪,我是猪,我是一只可爱的粉红pig") == 0)//两个字符串在比较内容时,不能使用==
{
system("shutdown -a");//取消关机
printf("关机被取消\n");
}
else
{
goto next;
}
return 0;
}
这个我就不演示了,感兴趣的可以自己试试。当然此处使用goto语句无非是想要就是循环,那么我们也可以使用while循环来代替:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char i[20] = { 0 };//字符数组,用来存放字符串
system("shutdown -s -t 60");
while (1)//死循环,直到有一次输入正确
{
printf("如果在1分钟内输入“我是猪,我是猪,我是一只可爱的粉红pig”就取消关机\n");
scanf("%s", &i);
if (strcmp(i, "我是猪,我是猪,我是一只可爱的粉红pig") == 0)//两个字符串在比较内容时,不能使用==
{
system("shutdown -a");//取消关机
printf("关机被取消\n");
break;//跳出去
}
return 0;
}
那么我的任务完成了,本人是C语言新手,如果有不足的地方,还请大家指出来。希望大家可以一起共同进步!谢谢大家!