C语言小游戏(一)----猜数游戏

目录

前言

猜数判定

if else 语句

重复到猜对为止(do语句,while语句)

随机设定目标数字

srand函数大显神功

限制次数并保存输入记录

尾声


前言

施律.C语言小游戏系列预计共有10个,较适合于已经学习完C语言入门内容,并想要掌握实际编程能力的程序猿。

猜数游戏在大家初学的课本上应该都有,难度系数不大,属于一遍过的那种程序。但再小的苍蝇也有肉啊!其实猜数游戏也包含了许多实用性的技巧。长话短说,接下来听施律.为渴望提升的你讲解C语言小游戏(一)----猜数游戏

猜数判定

先来个测试版的“猜数游戏”。通过if else语句、scanf函数键入数值和“目标数字”进行比较,并显示出比较的后果。

#include <stdio.h>

int main()
{
	int no;
	int ans = 5;

	printf("Please guess0--9:\n");

	printf("是多少呢?\n");
	scanf("%d", &no);

	if (no > ans)
		printf("Too big!\n");
	else if (no < ans)
		printf("Too small\n");
	else
		printf("Yes!You are right!\n");     \\    \n是一种转义字符,表示换行

	return 0;
}

本游戏设立的数是5。如果输入的数小于5,则输出Too small!;如果输入的数大于5,则输出Too big!。

if else 语句

本程序中的if语句采用以下形式。

if(表达式)语句 else if(表达式)语句 else 语句

其中的else if可以是很多个,这取决于程序猿想要设计的条件个数。

接下来我们讨论讨论多分支的方法,即用上述语句更另外2种if else 形态语句进行对比,得出优劣。话不多说,上代码!

if(no > ans)
    printf("Too big!\n");
else if(no < ans)
    printf("Too small!\n");
else
    printf("Yes!You are right!\n");          //1



if(no > ans)
    printf("Too big!\n");
else if (no < ans)
    printf("Too small!\n");
else if (no == ans)
    printf("Yes!You are right!\n");          //2



if(no > ans)
    printf("Too big!\n");
if (no < ans)
    printf("Too small!\n");
if (no = ans)
    printf("Yes!You are right!\n");          //3

我们来分析一下程序2、3较于1看看能得出什么结论。程序2较程序1追加了(no==ans)判断,这其实是非常多余的;程序3的三个if并列,无论no和ans之间的大小关系如何,程序都会对这三个条件进行判断。

接下来我们再通过图表的方式分析程序1、2、3所进行的判断,看看能得出什么结论。下面的【1】判断no>ans,【2】判断no<ans,【3】判断no==ans。

大小关系 no>ans时 no<ans时 no==ans时
1 【1】 【1】【2】 【1】【2】
2 【1】 【1】【2】 【1】【2】【3】
3 【1】【2】【3】 【1】【2】【3】 【1】【2】【3】

由上可以得出,程序1的效率是最高的

重复到猜对为止(do语句,while语句)

上个程序只允许玩家输入一次数值操作起来是十分无趣的。所以我们将程序改良一下,让玩家可以一直重复输入直到猜对为止。那我们该如何实现输入多次呢?我们学到的循环该派上用场了。利用do语句循环实现多次输入,代码如下:

#include <stdio.h>

int main()
{
	int no;
	int ans = 7;

	printf("请猜一个0-9的数。\n\n");

	do {
		printf("是多少呢?\n");
		scanf("%d", &no);

		if (no > ans)
			printf("Too big!\n");
		else if (no < ans)
			printf("Too small!\n");
		else
			printf("Yes!You are right!\n");
	} while (no != ans);

	return 0;
}

do语句是先循环后判断的,跟它的好兄弟while语句和for语句不同(后面会讲到)。在运用到do语句的过程中要时刻记得它的末尾是有分号“ ; ”的。如上所示,do 语句的控制表达式是no!=ans,运算符!=对左边和右边的操作数的值是否不相等这一条件进行判断。如果这个条件成立,程序就会生成int型的1表示继续,不成立则生成int型的0表示循环结束。

接下来我们看看用while语句实现猜数游戏:

#include <stdio.h>

int main()
{
	int no;
	int ans = 7;

	printf("请猜一个0-9的数。\n\n");

	while (1) {
		printf("是多少呢?\n");
		scanf("%d", &no);

		if (no > ans)
			printf("Too big!\n");
		else if (no < ans)
			printf("Too small!\n");
		else
			break;
	}
	printf("Yes!You are right!\n");
	
	return 0;
}

while语句是先判断后循环,跟前面的do语句的循环方式是不一样的。如上,while的控制表达式是1,所以循环会永远进行下去。这样的循环岂不是“无限循环”?那这样的循环该如何破解呢?break语句大显神功,直接强制跳出了循环语句。

随机设定目标数字

在前面的游戏中,自己设定的数自己猜显得太枯燥无趣了,要是能随机生成数字来猜则会增加很多的趣味性。仔细想想,我们好像能用rand函数来生成随机数。rand的功能是计算0-RAND_MAX(很多初学的小伙伴不知道RAND_MAX,这其实是头文件<stdlib.h>包含的一个宏,规定它的值不能小于编译环境所规定的最小数,最小为32767)的伪随机整数序列。何为“伪”?且听我一一分析。先上代码:

#include <stdio.h>
#include <stdlib.h>        

int main()
{
	int retry;          //再运行一次?

	printf("在这个编译环境中能够生成0-%d的随机数。\n", RAND_MAX);

	do {
		printf("\n生成了随机数%d。\n", rand());

		printf("再运行一次?  (0)否(1)是:");
		scanf("%d", &retry);
	} while (retry == 1);

	return 0;
}

聪明的小伙伴可以自行ctrl+c到编译器上看看,多执行几次程序会发现生成的随机序列是一模一样的!rand函数看似生成随机实则不随机,是有一定规律可循的。为什么呢?这是因为rand函数的默认种子(rand函数是对一个叫作“种子”的基准值加以运算来生成随机数的)是1。如果我们想要生成不同的随机序列,就必须更换种子的值。

srand函数大显神功

srand函数就能解决上面所描述的窘境。它的功能是给后续调用的rand函数设置一个种子,用于生成新的伪随机数序列。如果用同一个种子的值调用本函数,就会生成相同的伪随机数序列。如果在调用本函数之前调用了rand函数,就相当于程序在一开始调用了本函数,把种子设定成了1,最后会生成一个种子值为1的序列。此外,其他库函数在运行时会无视本函数的调用。

该怎么表示呢?打个比方srand(50)和srand(40),它们生成的随机序列是不同的,且看下表:

种子为50时,生成235->666->777->231->3489.....
种子为40时,生成222->2678->2235->1463->87.....

接下来我们要想把种子从常量变成随机值,可引用头文件<time.h>的time(),通过把运行程序时的时间当作种子来实现。上代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
	int retry;

	srand(time(NULL));

	printf("在这个编译环境中能够生成0-%d的随机数。\n", RAND_MAX);

	do {
		printf("\n生成了随机数%d。\n", rand());

		printf("再运行一次?  (0)否(1)是:");
		scanf("%d", &retry);
	} while (retry == 1);

	return 0;
}

RAND_MAX在上文中提到它所生成的数可能是非常大的,几万几十万都有可能。那么我们该怎么控制srand生成的随机值呢?我们可以运用求余运算来实现。普及一下求余的概念。请看下面:

rand()%6       是生成0到5的随机数,因为求余运算得出的结果是不会大于被余数的

、我们再对上述代码进行修改:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
	int retry;

	srand(time(NULL));

	printf("在这个编译环境中能够生成0-%d的随机数。\n", RAND_MAX);

	do {
		printf("\n生成了随机数%d。\n", rand());

		printf("再运行一次?  (0)否(1)是:");
		scanf("%d", &retry);
	} while (retry == 1);

	return 0;
}

这样游戏玩起来就不会枯燥乏味了!但好像缺少了点紧张刺激,我们应该再对该程序进行升级----限制次数并保存输入记录

限制次数并保存输入记录

如果游戏能够限制玩家的输入次数和保存玩家输入的值,玩家的游戏体验一定会有大幅度的升级!想到保存输入的值,我们肯定能联想到用数组保存。通过数组遍历,将玩家输入的值一一存入,并在游戏结束后呈现给玩家,让玩家知道自己猜的数字距离目标数字有多近。先上代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAX_STAGE 10

int main()
{
	int i;
	int stage;           //玩家已经操作的次数
	int no;
	int ans;
	int num[MAX_STAGE];        //玩家能操作的最大次数

	srand(time(NULL));
	ans = rand() % 1000;

	printf("请猜一个0-999的整数。\n\n");

	stage = 0;
	do {
		printf("还剩%d次机会。是多少呢: ", MAX_STAGE - stage);
		scanf("%d", &no);
		num[stage++] = no;

		if (no > ans)
			printf("Too big!\n");
		else if (no < ans)
			printf("Too small!\n");
	} while (no != ans && stage < MAX_STAGE);

	if (no != ans)
		printf("很遗憾,正确答案是%d。\n", ans);
	else
	{
		printf("Yes!You are right!\n");
		printf("您用了%d次猜中了。\n", stage);
	}

	puts("\n--- 输入记录 ---");
	for (i = 0; i < stage; i++)
		printf(" %2d:%4d %+4d\n", i + 1, num[i], num[i] - ans);

	return 0;
}

我们来分析分析上面的代码。

(1)先讲一个错误的例子。初级程序猿经常会犯这样的错误

int n=10;
int arr[n]={0};

乍一看貌似和上面的差不多,但实际上这是错误的写法。而先定义一个宏,再在数组【】中引用宏则是正确的写法;

(2)代码num[stage++]=no;是后置++,其利用for循环来对stage数进行增加。通过反复的循环处理,即可把玩家输入的值按顺序依次存入数组。

(3)在这段代码中我们运用了上面未曾讲到的for语句来显示输出记录。我们将这段代码拉出来单独讲解:

for (i = 0; i < stage; i++)
		printf(" %2d:%4d %+4d\n", i + 1, num[i], num[i] - ans);

首先把i的值设为0,当i的值小于stage时,就不断往i的值上+1,以此来让循环体运行stage次(stage的值等于玩家输入数值的次数)。

%2d %4d  符号与字母之前的数字代表它们的域宽,而%+4d中的+4是将数字向右靠齐。

下面的·代表一个空格,以125为例
%4d     125·
%+4d    ·125

尾声

以上就是施律.对本系列第一个游戏----猜字游戏的理解与分析,感谢能观看到这里的你!如果觉得本篇博客对正在学习编程的你有帮助的话,请给施律.多一点的支持与关注!接下来的10多天时间里施律.将和大家畅玩其他用编程实现的游戏,希望下次的我能为大家奉上更好的游戏,也希望下次的博客有你!


 

猜你喜欢

转载自blog.csdn.net/qq_64263760/article/details/122880908