程序开发剖解圣经(003)

公开课的准备(二)

       是否坚定了学生学习C/C++的念头,我并不确定,但有一点我可以确定,那就是,我的公开课还有一部分没有完成,那就是一个能够提起学生兴趣并能够比较快速实现的小游戏。

       我不想一开始就打开vc++,然后拿着一个现成的代码就开始演示或讲解代码,那估计会有很多学生晕头转向,甚至会睡着。

       到底该怎么来讲解这个游戏程序呢?于我来说,这是个再简单不过的小程序了,坐在那里不出半个小时,就能顺利完成,但学生能从你的书写里面收获多少东西呢?如果能做到即便学生听不懂看不懂你的程序,但依然有所收获,我就积了功德了。教师这个工作,是个良心活,我既然看不起应付教学,草草了事的老师,那就一定不能成为这样的老师。因此,我开始思索我八年来做项目的一些经验总结,希冀从里面能获得一些有用的灵感。

       很快,我想定了一个方案,那就是以一个真正的项目开发流程的模式讲解这个游戏。当然,要把一个项目的整个开发流程都讲解完,也不太现实。因为只项目运作过程,就有大量的知识量,那不是短时间能讲完的。更何况,这远偏离了公开课的初衷,更亵渎了学生们抽出时间来听课的原因,使得一个原本有意义的公开课也变得可有可无了。因此,我思定之后,决定抽出一部分项目开发内容,串成线,自然地去讲解出来。

          既然当做项目来讲,首当其冲,我们要分析项目需求,公司接一个项目,很多时候,用户本身都不清楚他要的东西应该包含什么功能,他甚至会把他想要的东西用一句话告诉你。大多情况下,他们是根据你的引导,或者看到相似的产品,不停地提出新的需求。而我们要做的,就是根据用户本身的业务范围,对他的功能内容进行细化,然后和用户敲定细节,这就是简单的项目需求分析了。需求在一个项目的整个生存期,很可能会出现这样那样的改变,但一个项目如果频繁的出现需求的变更,那要么可能是前期的需求分析出了问题,要么一定是前期需求分析出了问题。说到这,我记得我曾看到一个调侃程序员话,说:杀死一个程序员,不需要用枪或刀,只需要把需求变更三遍就可以了。这反映了一个现实情况,现实情况就是很多项目的需求分析都难以做到位。因此导致了需求的不停变更,最痛苦的,莫过于程序员了,因为任何一个需求的变动,客户都不会让你延长交付时间为代价。而根据需求更改代码,有时候是伤筋动骨,甚至连架构都要重构,这就是为啥程序员不停地加班工作的主要原因之一。以至于竟然有美女在网上发言:宁给捡破烂的当小三,也不嫁给程序员。这很伤程序员的自尊,但现实几乎真是这样的。所以,一般来说,单身几乎是程序员的标识,如果一个人脱离了单身,那他基本也快要脱离程序员了。我想,这应该就是中国程序员的悲催现状,也是为啥说程序员职业是青春饭的原因吧。

       我起初似乎大概也许只说了一句话:编写一个打字练习游戏。现在我们来细化需求:

       既然是打字游戏,那一定是从键盘输入字符和程序中的字符进行匹配的过程了。既然是游戏,那一定得有“通关文碟”,即过关条件,这里的条件,肯定是正确率了。很自然,我们亦能想到,每关的打字速度应该不一样。当然,程序中生成的字符应该是随机生成,否则玩游戏的人摸到了规律,还有意愿继续玩下去么?再有就是,用户在玩的过程中,可能会随时退出该游戏,而做其他事情,我们不能不让他退出。

       通过上面的分析,我想我们会很快给出如下几个需求:

1、  程序每次生成的字符是随机生成的。

2、  设定游戏的关数。

3、  控制游戏的速度。

4、  设定通关的正确率

5、  设定程序退出方法。

项目需求分析完成之后,我们接下来就要做软件需求分析。这里会生成一个文档,叫《软件需求规格说明书》。很显然,项目需求分析也会生成一个文档《项目需求分析说明书》,他的目的之一也是为程序员提供书写《软件需求规格说明书》的依据。

软件需求分析,和项目需求分析不一样,项目的需求分析是为了弄清楚用户的功能需求,而软件需求分析则是对每个项目需求的进一步细化,细化到什么程度合适呢?这每个公司并不一样,但有两个条件可以作为判断依据:1、细化到能够进行项目架构,指导后续《软件设计说明书》的编写。2、细化到测试人员可以用它来清晰准确的写出系统测试用例。因此,《软件规格设计说明书》应该是项目开发中非常重要的一环。它的成败,直接影响到项目的成败。

我们这里也来对项目需求进行进一步细化。

针对字符的随机生成,确定生成方法和生成范围。你总不能超越键盘之外吧,另外,你生成的东西也得要屏幕能显示出来吧。针对游戏的关数,我们的设计不能过少,过少了,用户一下子就通关了,感觉没意思,也不能过多,多了用户可能玩的过程中,玩反感了,干脆就不玩了。同样,游戏的速度也不能太慢,每关也应该有一些稍微明显的速度变化。把一个有些的速度设计到快的没人能完成,那这个项目也算失败了。太慢,当然也不行,你不能鄙视人的能力吧。既然是打字游戏,我们的目的就是让用户能熟练的使用键盘,因此,正确率必须是合适的设定。总不能让用户正确不到一半就算通关吧。每次吃个半饱就让你干活,你愿意么?程序当然要能退出,否则用户忍不住,说不定会过来敲你的头,万一受不了掐死你也正常。有些软件故意设定不让用户退出,想以此来提高它的市场占有率,结果却得不偿失,就是这个原因。耍流氓的结果最终是被流氓耍。

              综上,我们得出如下的软件需求。

1、在100 *60的范围内随机生成一个随机字符,只生成小写a~~z的26个英文字符。

2、游戏的关卡设定为10关。

3、第一关字符屏显时间为1秒,每过一关,屏显时间减少100毫秒。

4、每关随机生成字符次数为100个,准确率达到95%进入下一关。

5、当用户通关或者在键盘上输入大写’Q’,则推出游戏。

好了,软件需求分析完成了,接下来我们就要设计我们的程序算法了。

即我们该进入《软件设计说明书》的编写了,确切的说,这里是两部分:

《软件概要设计说明书》和《软件详细设计说明书》,但很多公司将这两个揉合到一起了,统称为《软件设计说明书》。这重点突出在了设计上,通过软件设计说明书,我们应该能完全准确的架构一个项目,指定项目的每个模块功能实现。搞定了软件设计说明书,项目可以说已经完成了一半了。好的软件设计说明书能够涵盖代码90%的内容,可以这么说,真正的编码程序员只需要根据设计说明书的要求,完成编码即可。算法甚至都不用思考,因此,“码农”一词,说的甚是亲切。毫不客气的说,刚进入程序界的,几乎都是码农,相当码农也非易事。

         好了,根据软件规格说明书,我们可以的得到如下内容。

函数一:界面显示

函数名

DWORD WINAPI  DispUI(LPVOID lp)

主调函数

Main()函数

调用函数

随机数函数rand();休眠函数sleep();

函数功能

Windows线程回调函数,实现字符在屏幕上的动态显示

入参

必选参数:LPVOID lp;回调函数进入参数

出参

函数返回值

DWORD

函数描述:

Begin:

用数组定义整个游戏屏幕的范围;

设定时间作为随即生成字符的种子。

While(字符不是游戏退出字符)

{

       随机生成一个字符;

       让其在随机指定的位置开始下落

   查看用户从界面输入的字符是否和随机生成的字符一致

   If(一致)

{

       正确统计值自增1;

       重新循环生成下一个字符

}

Else if(不一致)

{

       循环生成下一个字符;

}

判断时间是否达到规定时间

If(到达规定时间)

{

       If(正确率不达标)

              继续该级别的训练

   Else

          进入下一关的训练;

}

Else

{

       继续本关的训练

}

设定各个字符产生的频率;

}

End:

函数二:入口函数

函数名

int main(void)

主调函数

系统调用

调用函数

线程创建函数,退出字符获取函数

函数功能

函数入口,用来创建打字游戏处理线程

入参

出参

函数返回值

Int

函数描述:

Begin

       调用CreateThread函数创建线程,线程的执行函数为DispUI;

   While(用户没有输入退出字符)

       {

              等待用户输入新字符。

}    

End

项目生成:

       Keyword.exe

至此,我们可以在设计说明书的帮助下进入到了编码阶段,具体的编码内容,如下:

/*********************************************************************

**文件名称:main.c

**文件功能:实现一个简单的打字游戏

**函数列表:DispUI(LPVOID lp)

              main()

**创建时间:2012-11-11

**创 建 人:new create by LLQ

**********************************************************************/

#include<stdio.h>

#include<stdlib.h>

#include<Windows.h>

#include<conio.h>

#include<time.h>

 

#define WIDTH   60   //屏幕的最大宽度

#define HEIGHT 100   //屏幕的最大高度

 

charg_chInput;     //用户输入字符信息;

int  nRightNumber = 0;          //统计正确的输入个数。

int  nTotalNumber = 0;      //统计总共的字母个数;

int   nSleepMultime = 1000; //最慢设定为1秒

float RightPercent= 0.0f;  //正确率

int   nQuit = 0;

/*********************************************************************

**函数名称:DWORD WINAPI DispUI(LPVOID lp)

**函数功能:线程执行函数,设定UI界面宽度,并产生下落字符

**函数参数:LPVOID lp

**创建时间:2012-11-11 Create by LLQ

**********************************************************************/

DWORD WINAPIDispUI(LPVOID lp)

{

     char Layout[HEIGHT][WIDTH];   //屏幕显示

     char Ch;

     char Row, Col;

     int i, j;

 

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

 

     while(g_chInput != 'Q')

     {

         Ch =rand()%26 + 'a';   //只处理小写字母;

          Row   = 0;                  //从0行开始                 

         Col     =rand() % WIDTH;   //生成该字母的下落位置。

         //休眠时间

         ++nTotalNumber;

 

         //该循环用来设置屏幕中每个位置的显示字符

         for(Row=0; Row<HEIGHT; ++Row)

         {

              for(i=0; i<HEIGHT; ++i)

              {

                   for(j=0; j<WIDTH; ++j)

                   {

                       Layout[i][j] = ' ';

                   }

              }

//每次下落一行,同一列的不同行保存该字符,相当于,每次下落一层。

              Layout[Row][Col] = Ch;

              system("cls");   //系统函数,用来清屏;

 

              //该循环吧下落到指定位置的字符打印出来,其他位置打印为空。

              for(i=0; i<HEIGHT; ++i)

              {

                   for(j=0; j<WIDTH; ++j)

                   {

                       printf("%c",Layout[i][j]);

                   }

                   printf("\n");

              }

              //键盘输入的字符和随机生成的字符是否一致,一致,则生成下一个字符。

              if(g_chInput == Ch)              

{

                   ++nRightNumber;

                   if(50 == nTotalNumber)

                   {

                       //每到100个字符,统计正确率,正确率达到95%,则加快速度

                       RightPercent =nRightNumber / nTotalNumber;

                       if(RightPercent >0.95)

                       {

                            printf("速度升级,加油哦!\n");

                            Sleep(2000);

                            nSleepMultime -=100;//设定管卡为10关

                            if(nSleepMultime>= 100)

                            {

                                 //重新开始统计新一关的正确率

                                 RightPercent =0;

                                 nRightNumber =0;

                                 nTotalNumber =0;

                            }

                            else

                            {

                                 printf("恭喜你,你的输入级别已经达到熟练!\n");

                                 Sleep(2000);

                                 nQuit = 1;

                                 return 0;

                            }

                       }

                       else

                       {

                            printf("抱歉,你本关不过关,需要重新修炼\n");

                            Sleep(2000);

 

                            RightPercent = 0;

                            nRightNumber = 0;

                            nTotalNumber = 0;

                       }

                   }

                   break;

              }

              Sleep(nSleepMultime);

         }

     }

 

     return 0;

}

 

int main(void)

{

     CreateThread(NULL, 0, DispUI, NULL, 0,NULL);

 

     //退出条件成立则退出该程序

     while(1 != nQuit || g_chInput != 'Q')

     {

         g_chInput = getch();

     }

     return 0;

}

 

至此,我的公开课准备完成。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值