【C语言】猜数字游戏的实现与解析(可能是本年度最详细的代码实现与解析)

您所在的位置:网站首页 描述一个游戏过程的小段 【C语言】猜数字游戏的实现与解析(可能是本年度最详细的代码实现与解析)

【C语言】猜数字游戏的实现与解析(可能是本年度最详细的代码实现与解析)

2024-01-08 11:36| 来源: 网络整理| 查看: 265

  前言:

  在写这一篇博客之前,我一直在想要用什么样的方式给大家展现出来,是先把整个工程完成再去讲每段代码?还是按照代码的实现过程去一步一步推进?或许两者随便哪个都行,但是我觉得,如果想要把一个知识点讲透了,让读者能够跟着自己的文章一起去思考,并且能够独立完成这个项目,那么,我需要做的就不止这点了。

目录

                              前言:

                     项目功能的逐步实现:

                  一:开始前的准备,需求分析

                  二:项目模块化

                  三,函数的实现

              1,main函数的设计

              代码解析:

     1)引用头文件的作用:

     2)使用do while循环的逻辑:

     3)switch 语句选择在本程序中的原理:

      函数测试:

              2,封装函数功能实现

       1)menu函数封装:

       2)game函数封装

              代码解析:

         1)生成随机数实现原理及方法:

2)设置所生成随机数范围的方法:

3)设置次数的逻辑:

  代码测试:

                  四,项目的总体预览:

            test.c

            game.c

           game.h

                  五,作者的话:

 

项目功能的逐步实现:   一:开始前的准备,需求分析

  作为一个1~100之间的猜数字游戏,需求分析如下:

游戏开始菜单进入游戏后,需要随机生成一个1~100之间的随机数当我们在猜数字时,要根据与被猜数的距离给出相应的提示设置猜的次数,超过次数则游戏结束游戏结束时需要能够继续让用户选择是否继续游戏

二:项目模块化

  在项目中,我本人比较建议大家尽量进行函数模块化,这样可以使代码逻辑更加清晰,不论是自己还是别人都能够很好地去阅读代码。

  例如:本项目我会分成三个模块:

test.c ————用于存放main函数game.c————用于存放自己封装的函数game.h————头文件,用于存放整个项目的声明

三,函数的实现   1,main函数的设计

  在写函数的功能之前,我们应当先想清楚程序的运行逻辑,故在写main函数时,若是需要什么功能,可先写个函数名以及他的功能,等主函数完成后,再去一一实现,这样有利于逻辑思考的连续性。

  根据需求分析得:该游戏需要提前打印菜单,并且用户可以选择开始或退出游戏,与此同时,该游戏在结束时需要能够让客户自行选择是否继续游戏。代码如下(选择用截图是因为编译器对关键字有颜色区分,可以看得清楚一点):

  代码解析:      1)引用头文件的作用:

       在代码第十行(左边行号)处有一段代码:#include “game.h” ,这个是包含我们自己所创建的头文件的作用 ,这样一来我们就可以把所有的函数引用,库函数头文件包含等等,通通写进game.h中,而我们只需要在主函数前包含这一个文件即可,如此可以使得代码看起来更简洁干净。

      (  如果是包含库函数的头文件就是写成:#include ,若是包含我们自己创建的头文件,就写成:#include “头文件名”)

     2)使用do while循环的逻辑:

        之所以使用do while循环,主要是因为无论用户是否开始游戏,函数都会先打印菜单。

     3)switch 语句选择在本程序中的原理:

       在主函数中,我设定了局部变量 input,并将其作为do while循环的判断条件。

       在do while循环的判断条件中,非0为真,0为假。所以1为真,我们可以在case 1 下存放游戏函数,当用户输入1时,便会开始游戏,并且在游戏结束时break跳到do while判定,因为1为真,故继续执行循环,打印菜单...以此类推

       而0为假,当用户输入0时,程序跳到case 0 语句再执行break跳出循环来到do while判定,因为0为假,故循环结束,退出游戏

        而且为了防止用户乱输入,我们还应当加上 default 以纠正。 (default:根据用户输入的值,执⾏相应的 case 分⽀。如果找不到对应的值,就执⾏ default 分⽀)

  函数测试:

    main函数的逻辑完善后,我们还应当检验其是否能够以正确的方式输出我们想要的值,该代码输出如下:

  可以看到,输出正常,证明逻辑没有出错。

 2,封装函数功能实现     1)menu函数封装:

  根据需求分析得,当用户执行程序时,需要菜单来选择自己是开始游戏或者退出游戏,所以我们需要封装一个 menu 函数用于打印菜单。而封装的 menu 函数放入game.c的源文件中(game.c也需要包含头文件game.h)。如下图:

  menu函数:这是我们自己封装的一个函数,主要作用就是打印菜单,所以无需传参,并且无需返回值,所以函数形式为:void menu();。  

  当我们完成函数的封装后,需要将函数的声明写入头文件中,如下:

2)game函数封装

  根据需求分析,可以得出game()函数应当具备以下功能:

   1,随机生成一个1~100之间的随机数

   2,当我们在猜数字时,要根据与被猜数的距离给出相应的提示

   3,设置猜的次数,超过次数则游戏结束

函数如下:

  该函数无需返回任何值,故返回类型设置成void,并且无需传参。同样的,与menu函数相同,需要将函数引用放置在头文件game.h中,如下:

  代码解析:   1)生成随机数实现原理及方法:

   在讲生成随机数之前,我需要先给大家铺垫三个函数:

  1,rand函数:C语⾔提供了⼀个函数叫 rand,这函数是可以⽣成随机数的。rand函数的使用需要包含头文件:stdlib.h。

  但是当我们多次输出rand函数时,发现每次输出的随机数是一样的,如下:

  不管运行多少次,所输出的随机值都与上一次结果相同,说明这是有问题的。

  如果再深⼊了解⼀下,我们就不难发现,其实rand函数⽣成的随机数是伪随机的,伪随机数不是真正的随机数,是通过某种算法⽣成的随机数。真正的随机数的是⽆法预测下⼀个值是多少的。⽽rand函数是对⼀个叫“种⼦”的基准值进⾏运算⽣成的随机数。

  之所以前⾯每次运⾏程序产⽣的随机数序列是⼀样的,那是因为rand函数⽣成随机数的默认种⼦是1。如果要⽣成不同的随机数,就要让种⼦是变化的。

   2,srand函数:C语⾔中⼜提供了⼀个函数叫 srand,⽤来初始化随机数的⽣成器的。

//原型为: void srand(unsigned int send);

   程序中在调⽤ rand 函数之前先调⽤ srand 函数,通过 srand 函数的参数seed来设置rand函数⽣成随机数的时候的种⼦,只要种⼦在变化,每次⽣成的随机数序列也就变化起来了。那也就是说给srand的种⼦是如果是随机的,rand就能⽣成随机数;在⽣成随机数的时候⼜需要⼀个随机数,这就⽭盾了。

   注意:srand函数每个工程只需要调用一次即可!

   3,time函数:在C语⾔中有⼀个函数叫 time ,time函数的使用需要包含头文件:time.h。

//原型为: time_t time(time_t*timer);

    time 函数会返回当前的⽇历时间,其实返回的是1970年1⽉1⽇0时0分0秒到现在程序运⾏时间之间的差值,单位是秒。返回的类型是time_t类型的,time_t 类型本质上其实就是32位或者64位的整型类型。

     time函数的参数 timer 如果是⾮NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。如果 timer 是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。

     如果只是让time函数返回时间戳,我们就可以这样写:

time(NULL);//调用time返回时间戳,这里没有返回接收值

  由上铺垫可得:我们如果用rand需要生成一个随机数,就需要调用srand函数来初始化rand函数的种子,而为了使种子随时在变化,我们就将时间戳设置为rand函数的种子,因为时间一直在变化,所以种子就一直在变化,同样的,随机数也一直在变化。

  代码形式如下:

srand((unsigned int)time(NULL));

   注意:srand函数一个工程只需要调用一次,故该段代码应当放在main函数中调用!

2)设置所生成随机数范围的方法:

  在我们设置好随机数后,需要再设置随机数的生成范围,在该项目中,我们需要生成1~100的随机数,方法及操作逻辑如下:

  假设随机生成一个数n,我们只需将 n%100,那么n%100的数字便会变成0~99,我们只需操作为:n%100 + 1;此时生成的随机数的范围便是1~100;

   推而广之,如果要生成a~b的随机数,方法如下:

  3)设置次数的逻辑:

  在game()函数中,我将猜数字设置成while循环,并且将局部变量times设为判定条件。每次进入循环(猜数字)结束后,times--,故当times=0时,while判定为假,结束循环,即可实现。

  代码测试:

 可以看到,代码的所以功能都在我的设想当中,故没有问题。当然,整个程序还可以更加好,提示也可以更加细致,如根据不同的距离显示不同的提示等等,但是由于时间原因,我只是写了一个主体出来,如果大家有兴趣的话,可以接着将其优化。

四,项目的总体预览: test.c #define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" int main() { int input = 0; srand((unsigned int)time(NULL)); do { menu();//菜单 scanf("%d", &input); switch (input) { case 1: game();//游戏封装 break; case 0: printf("退出游戏\n"); break; default: printf("非法输入,请重新输入\n"); break; } } while (input); return 0; }

game.c #define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" void menu() { printf("************************\n"); printf("************************\n"); printf("******* 1:> play *******\n"); printf("******* 2:> exit *******\n"); printf("************************\n"); printf("************************\n"); return; } void game() { int count = rand() % 100 + 1; int find = 0; int times = 8;//猜数字次数 while (times) { printf("\n"); printf("你还有%d次机会 ",times); printf("请输入您要猜的数字:> "); scanf("%d", &find); if (find < count) { printf("您猜小了,再猜大一点的数字\n"); } else if (find > count) { printf("您猜大了,再猜小一点的数字\n"); } else if (find == count) { printf("恭喜您,猜对了!\n"); break; } times--; } if (times == 0) printf("游戏失败,正确数字为%d\n",count); return; }

game.h #pragma once #include #include #include void menu(); void game(); 五,作者的话:

 整篇文章,我对于一些比较简单的内容讲的比较细致,比如switch语句,设置次数等等,主要是想帮助一些不懂的朋友理解这个代码这样写的原因,如果您觉得啰嗦了,可以在评论区留言,以便我下次改进。

 目前我在考虑写一个有关扫雷实现的博客,但是扫雷我还有几个功能一直没能实现,等我彻底搞明白之后就会和大家分享!

  谢谢大家的观看,再见!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3