大家好,我是蓝天白云!在这篇文章中,我将向大家介绍前一段时间我的编程经历。首先要提醒大家的是,这篇文章的内容较为丰富,涉及面很广,同时也十分有趣,不过由于信息量比较大,所以希望大家在有空时慢慢阅读,相信你能体会到其中的乐趣的!如果大家准备好了,那我们就开始吧!
记得在上个学期,我选修了一门专业选修课“数值计算方法(2)”。这门课每周都有一次上机实验课,老师会布置一些题目,让我们编程计算。这门课主要用的编程语言是MATLAB。由于之前在“数值计算方法(1)”的课程中我已经自学了MATLAB,所以现在用MATLAB实现一些小算法也并不感到很困难。在前几周的课程中,老师布置的上机实验内容都较少,因而,每次完成老师布置的任务后,我都可以留出一段时间来自修。这段自修时间用来干什么呢?一个自然的想法是继续学习书后面的知识,然而考虑到这样做或许会减少后来真正学到那里时的学习热情,所以我并没有这样做。后来,我又考虑自学Python(由于我的学业导师做的研究中常用Python,因此我也很有必要学习一下),但由于当时收藏了B站上小甲鱼的Python教学视频,看上去是很不错的教学资源,因此,我打算通过观看这部视频来学习Python,但在机房中不方便打开声音,也不方便戴耳机,所以最终我还是放弃了在学校机房学习Python的想法。这样思来想去,实在拿不定主意,最后,我的目光还是落在了我熟悉的C++编译器MinGW上,萌生出了这样的想法:要不我就自己用C++随便做一个小游戏玩玩解解闷吧!虽然这样做好像有点贪玩的嫌疑,但这也可以理解成是在练习编程,所以如果被老师发现的话,应该也不会怎么样吧?这样想着,我便开始尝试编起第一款小游戏来。那是一个非常简单的程序:生成一道随机的三位数的加法题,键盘输入答案,电脑判断正确与否,这样无限进行下去。虽然十分简单,但当我编程实现功能以后,还是感到很开心,并且还不禁玩上了瘾。就是这样简单的一个人机互动过程,使我感受到了电脑游戏最原始,最单纯的乐趣。
有了这第一次尝试做热身,此后便一发而不可收。在之后每次上机课的自修时间中,我开始奇思妙想,尝试编写一些更复杂的小游戏;同时,我也不断借鉴我曾自己玩过的,还有看别人玩过的一些有趣的小游戏,把它们进行改编,也纳入到我的小游戏中。几周之后,我有了更大的“野心”。我打算编写一个大程序,把我编过的所有小游戏都加入进来,玩家可以想玩哪个就玩哪个,而且最好还能有一些得分记录。然而,随着课程的进行,每次上机课布置的任务越来越多,我逐渐没有了自修的时间,而我的小游戏合集工作量又过于庞大,我只好再抽出课余时间来将其编写完善,到后来,消耗的课余时间甚至都比上机的自修时间要多得多。更为甚者,当我在着手写这篇日志的时期,我也在仍在不断修改完善代码。编写我的小游戏合集已经俨然成为了我的“日常工作”。不过,看到一款又一款小游戏完成,自己想要的功能一个又一个实现,喜悦之情还是不断涌上心头。所有的付出都是值得的!终于,我在今天(2020年12月27日)完成了这部作品——蓝天白云小游戏集!
这可以算是一款综合向的益智游戏,考验了玩家的计算力、观察力、记忆力、反应力、推理力等各项能力,是对脑力的综合测试。下面,进入这篇日志的主体部分,我将介绍我所编写的小游戏集的全部游戏的规则与由来。
1.加减速算
本游戏考验计算力。这款游戏的原型就是我在学校编写的第一款游戏!不过,为了增大难度,我在原游戏的基础上还加入了减法题。题数固定为20题,游戏结束后会统计正确的数量以及所用的时间。虽然说这款游戏不管从实现上还是游玩上都很简单,但我还是保留了它。毕竟这款游戏对我来讲还是有特殊的纪念意义的!同时,因为玩起来简单,所以把这款游戏用作热身也是很不错的。
2.乘法估值
本游戏考验计算力。这同样是一款与数学密切相关的游戏,具体玩法是这样的:屏幕中会出现5个二位数乘以二位数的算式,我们不需要准确计算它们的结果(当然你想算也可以),而是需要将它们的结果从小到大排序,共10题,游戏结束时会统计正确数量与所用时间。和上一款游戏相比,这款游戏不需要太精确的计算,而是需要一些数学直觉与估算技巧。看上去似乎比较容易,但要想做到快速准确,还是颇有难度的。具体的技巧我就不多介绍了,大家可以自行尝试总结。
前两款游戏都比较简单基础,只是单纯的数学题。设计这两款游戏的原因也很简单,毕竟我是数学系的学生嘛!虽然平时的课程中和我们打交道的往往是一些抽象的符号,但是我对具体的计算也是持有浓厚的兴趣的。这里再和大家分享一点关于提升计算能力的小心得,或者说是我的个人习惯吧。不知道大家在做计算时对计算器的依赖大不大。其实,在做一些加减法,以及数位不大的数字之间的乘法时,我已经基本可以做到不用计算器,仅靠心算就得出答案了(乘法可能需要一点时间,而除法可能存在除不尽的问题,较为困难,就暂时没有考虑)。当然,对于一些世界级心算大师来说,这肯定是小巫见大巫了。一部叫做《最强大脑》的节目中曾经就有过心算的比拼,似乎最简单的题目也有六位数乘以七位数,而选手没过几秒就能给出答案,那种程度对我来说,当然还是望尘莫及的。
但我自认为在普通人当中,我的心算能力应该还是不错的。我认为一部分原因是我先天对数字比较敏感吧,同时对数学也有浓厚的兴趣,所以从小学开始,数学就一直是我的强项,后来到大学,我也是遵循着我的兴趣,选择了数学专业。另一部分原因的话,应该是来自强制自己少用计算器,逐渐锻炼出来的。我觉得心算是锻炼大脑的一种不错的方式,在日常生活中,我偶尔也会自己给自己随机出一道三位数以内的乘法,心算出结果,最后用计算器验证。这样的过程可以让大脑运转起来。所以我也提倡大家减少对计算器的依赖,多多动脑有益智商!
3.数字破译
本游戏考验推理力。这是一个十分经典,也十分有名的小游戏——猜数字的复刻版。游戏玩法是这样的,电脑随机生成一个没有重复数字的四位数码(首位可为0),我们共有10次机会来猜这个数码是什么。每猜测一次,电脑都会给出一条信息“xAyB”。其中x代表我们猜的数码中数字正确且位置也正确的数码的个数,y代表数字正确但位置不正确的数码的个数。例如,当正确答案是7104时,如果猜1234,那么就是1A1B,1A是因为4这个数字在正确答案中出现了,并且猜的位置也正确,1B是因为1这个数字在正确答案中出现了,但位置不正确。之后,我们可以根据这一信息做推理,然后继续猜测,直到猜中(4A0B)或次数用完为止。由于这款游戏有一定运气成分,所以为了能够更好地反映出玩家的真实水平,我将游戏设置成了每次游玩都会连续进行三轮游戏,最后取每轮游戏结束后剩余的猜测次数之和作为最终成绩。由于这款游戏是以推理为主,故不将时间作为成绩的一部分。
这是我编写的第一款有一定背景的游戏。其实关于选择复刻这款游戏,还有一段故事,在这里也和大家分享一下。在我童年时,妈妈曾教过我许多益智游戏,这款游戏就是其中之一,这些游戏,或许是我的思维能力的启蒙。不得不提的是,妈妈玩这些游戏真的很厉害,几乎是完全碾压我的程度。记得那时候我和妈妈玩猜数字,二人互相出题。不管我怎么绞尽脑汁出一个看似很难猜的数字,妈妈总是能够经过最多五六步的推理就准确猜中,而轮到我猜的时候,我总是胡猜乱猜,往往十次机会用完了还猜不中(甚至到现在我也没有底气说能够玩得很好)。不过不管怎么样,童年的那段和妈妈一起玩耍的时光,还是令我十分难忘的回忆。
十几年过去了,这款游戏似乎一直沉睡在记忆中。直到前不久,我的妈妈无意中再次提到了这款游戏,说是好久没有玩过了,很怀念。妈妈的话语重新勾起了我多年前的回忆。这时,我灵光一闪。想到我已经学习了不少C++编程的知识,或许我有能力将这款游戏亲自编写出来,这应该会是很有纪念意义的事情。说干就干,在妈妈的话刚说出去不久,我就开始敲起了代码。进程比想象中顺利得多,只用一个小时不到,我就成功复刻了这款游戏!当我把程序发给妈妈,两人一起重温这款游戏时,真的还是让人感到十分怀念,也十分温馨的。童年的美好记忆,我会永远留在心中。
另外,值得一提的是,著名电子游戏开发公司任天堂在今年六月推出的《世界游戏大全51》中也收录了一款类似的游戏:“猜颜色”。
和猜数字相比,猜颜色中总共只有6种颜色来搭配,因而比10个数字的搭配要简单不少。不过猜颜色中还加入了一种高难度模式,在这一模式下,可能会出现重复的颜色,这会将答案的范围扩大不少。我本来也想在我的程序中加入类似这样的高难度模式,但想到10个数字本来就比6个颜色多了,如果再允许重复,可能难度会提高太多,所以最终我还是没有这样做。再顺便一提,我在今年暑假发布的一个视频系列Jingle Jam中也曾出现过“猜颜色”的游戏,看来这款游戏还真是风靡全球啊!
4.火眼金睛
本游戏考验观察力。这是一款容易让人眼花缭乱的游戏!计算机会随机选取5个可打印字符,用这些字符随机生成一个10*10的方阵,其中5种字符的出现数量依次为24、22、20、18、16,你要从中找出你认为出现次数最多的那个字符,输入给电脑。对应于出现数量依次为24、22、20、18、16的字符,分别可以得到5分、4分、3分、2分、1分。如果你所打的字符根本就没出现,则一分不得。共10题,游戏结束后统计总分数与所用时间。这款游戏的玩法乍一听或许会让人觉得觉得不太难,但实际玩起来,还真有点棘手!尤其是遇到相似度很高的字符的情况,真的是让人眼花缭乱。
这款游戏的设计灵感,应该来自于两方面。一方面是源自于网上经常见到的眼力测试,即在一大堆重复的字符中找出一个不一样的,或是在一大堆重复的颜色中找出一个不一样的。
另一方面是源自任天堂开发的游戏《马里奥聚会10》中的一个小游戏。这款小游戏的具体名字我没能考察到,不过其玩法是这样的:一块矩形的大屏幕会被几条线划分成若干个不规则多边形区域,几位玩家要在短时间内选择自己认为面积最大的区域,选择的面积越大,得分就越高。
结合了以上两方面制作出来的这款游戏,我认为玩法还是比较简单有趣的。这款游戏的难点在于如何又快又准,这还是很考验眼力的,因此想要得到好成绩并不容易。
5.过目不忘
本游戏考验记忆力。这款游戏的玩法很容易理解:计算机会随机生成一个5*5的数表,里面包含数字1至25,你需要花一段时间将其中所有数字的位置记住,记忆时间结束后,表中的元素会全部变成问号,你需要将数字所在的位置一个一个输入,从而还原这张表。
这款游戏其实源自任天堂的游戏《脑锻炼》中的一个测试内容,不过我对其做了些许改编。《脑锻炼》中这款游戏的记忆时间与作答时间均为2分钟,而在我复刻的版本中,玩家可以自选记忆时间(不超过2分钟),而作答时间不作限制,最终以作答正确数与记忆和作答所用的总时间作为最终成绩。我认为这样改编的话,有能力的玩家可以有更多的发挥空间。
这款游戏对短时记忆的考验还是比较大的,25个元素(包括数字与方位等信息)的记忆量并不小,选择恰当的记忆方式与作答方式是成功的关键。事实上,我在记忆力方面也并不擅长,因此也就不多说什么了,大家可以自行总结经验。其实,将这款我不擅长的有关记忆力的游戏加入合集中,也是想让这个游戏合集能够全方位地锻炼玩家(包括我自己)的各项能力,避免玩家偏科。
当然,如果你在记忆过程中用手机拍一个照,自然可以不费吹灰之力就能将所有数字“记住”,但这种作弊方式是绝对不提倡的,用这种方式获取的成绩没有任何意义。随着现在技术越来越发达,不管是什么游戏,总是可能存在一些作弊手段。就像前一阵子很火的游戏糖豆人,其中就有不少外挂的存在,破坏了很多人的游戏体验。任何理性的人都知道这样作弊是很没有道德也很没有价值的事情,除去满足自己的虚荣心外,对自己的能力不会有半点的提升,我相信大家也都能懂得这个道理。
6.勇者对决
本游戏考验反应力。这个小游戏比较有意思,是经典游戏“快枪手”的复刻改编。玩法可以这样理解:想象两位西部牛仔正在进行对决,听到“Fire!”口令后,双方快速开枪射击对方,反应更快的人获胜;若提前开枪,则算作违规,直接判负。在任天堂发布的派对游戏《1 2 Switch》中就有“快枪手”的小游戏,可以进行双人对战,并且还会有帅气的动画演示和回放,有兴趣的朋友可以搜索一下(本文提到的所有任天堂的游戏我都没有亲自玩过,都是通过别人的视频或直播了解到的)。
当然,我自然没有能力做出这么逼真的情景画面,因而在我的程序中,实际的游戏过程是:玩家要紧盯屏幕,等待“Fire!”字样显示,随后以最快的速度按下键盘上的任意键(代表开枪),如果反应时间在一定范围内,则判胜,否则判负。游戏共进行5轮,每轮的等待时间随机,但是平均来讲是依次递增的,而反应时间却是依次递减的,最终以胜利的次数与总反应时间作为最终的成绩。顺便一提,为了模拟出更逼真的效果,当Fire字样显示的同时,我还加入了响铃字符(十进制ASCII码为7的字符)来模拟开枪的信号,这应该会增添一定的游戏效果。不过经过测试发现,响铃声音的真正出现似乎比Fire字样的显示要延后一点点,因而如果只听声音不看屏幕,或许不能玩得很好,这还是比较遗憾的一点。
7.信任进化
本游戏考验推理力。这个小游戏的玩法源自新加坡独立游戏开发者Nicky Case制作的一款出色的独立游戏《信任的进化》。这款游戏以这样一个小游戏展开:
假设现在有两个人:你和你的对手,你们每个人都有两种选择:合作或欺骗。如果两人都选择合作,则合作达成,两人都可以得到2个金币;如果两人都选择欺骗,则两人都不赚不赔;如果一人合作而另一人欺骗,则欺骗方可以得到3个金币,而合作方却要失去1个金币。面对这样的情况,你会作何选择呢?
实际上,这是一门叫做博弈论的学科中的一个经典问题(类似的博弈问题还有囚徒困境,智猪博弈等)。《信任的进化》这款游戏就是以这样一个博弈游戏为基础展开,层层深入,向我们展示了这样一个简单的博弈能够给我们带来的种种启示。由于后文可能会含有一些游戏的剧透,对这款游戏感兴趣的玩家可以先自行体验一下这款游戏。游戏不长,十几分钟即可通关。我最初是通过B站UP主lolo今天玩什么的视频“人类的本质就是复读机?”了解到的这款有趣的游戏,进而对博弈论产生兴趣的。进一步,我在去年选修了学校的通识课“身边的博弈论”,对博弈论有了更深的理解和认识,因而,我也就有了把博弈论加入我的小游戏合集的想法。
我们先回到《信任的进化》,再来仔细分析一下刚刚提到的博弈小游戏。为了简化,我们把合作简称A,把欺骗简称B,把这个博弈游戏称为AB游戏(这样的叫法沿用了另一款游戏《极限脱出之善人死亡》的叫法,那款游戏中,也有类似的博弈游戏)。根据博弈论的知识,我们可以画出如下的博弈矩阵:
分析博弈矩阵可以得到,如果对手选A,我们选择A是+2,选B是+3;如果对手选择B,我们选A是-1,选B是+0。因而,无论对手选A还是选B,我们选B永远都会比选A要好,这样看来,B似乎是永远都不会错的选择(在博弈论中,B叫作绝对占优策略)。但是,再仔细想想看呢?如果两个人永远都互相欺骗,那么双方都得不到好处,这显然不如双方同时合作要好。因而,我们也可以得出这样的结论:绝对占优策略未必能导向最佳的结果。那么,从中我们又可以得到什么启示呢?当仅有一次博弈的时候,我们无法知道对手是一个什么样的人,因而为了自身的利益最大化,选择欺骗是比较合理的;但如果博弈的次数不是一次,而是多次,我们或许就可以了解到对手的性格特点,从而有望逐步建立信任,实现双方的合作共赢,这也就是游戏标题《信任的进化》的由来。
在《信任的进化》的游戏过程中,我们会认识到8种具有不同性格的人物,他们是:
复读机:第一次会选择合作,此后开始不断重复玩家上一次的行动。
千年老油条:永远选择欺骗。
万年小粉红:永远选择合作。
黑帮老铁:第一次选择合作,如果玩家在任意一次选择了欺骗,此后就会永远选择欺骗。
福尔摩星儿:前四次会选择合作、欺骗、合作、合作。如果玩家从未选择欺骗,其从第五次开始就会一直选择欺骗,而如果玩家在任意时候选择了欺骗,其就会像复读机一样重复玩家上一次的行动。
复读鸭:前两次都选择合作,此后只有当玩家上两次都选择欺骗时,才会选择欺骗。
一根筋:第一次选择合作。此后如果玩家选择合作,其下一次就会做出和上一次相同的行动;如果玩家选择欺骗,其下一次就会做出和上一次相反的行动。
胡乱来:以同等的概率随机选择合作或欺骗。
这8种角色其实都是不同性格的人物的代表,譬如小粉红代表的就是单纯的人,复读机代表的就是互惠宽容的人(你合作我也合作,合作共赢;你欺骗我也欺骗,以牙还牙,这种人是非常普遍的),胡乱来代表的是非理性的人等等。游戏正是基于这8种人物之间的博弈,分析了人类信任进化的方式。总之,这是一款制作十分精美的独立游戏,既有直观的画面演示,也有深刻的思想解读,再次推荐大家尝试一下。
而相比之下,我设计的小游戏就显得简陋许多了,仅仅是借用了以上8种人物的设定和AB游戏的玩法拼凑出来的一款游戏。具体玩法是这样的,8种人物会以乱序出现,且每种人物会先后出现两次。按照出现的先后顺序,他们会被分别标记为ABCDEFGH,你并不知道这些人物的真实身份,只能通过和他们的博弈来推测。每一个人物出现,你都要和他们进行8回合的AB游戏(规则和《信任的进化》中的完全一样),所有人物出现完两次后,以玩家最终拥有的金币数作为最终的成绩(由于本游戏以推理为主,故不计时间)。
对于这一玩法,还有一些需要解释的地方。首先,严格来说,我的这款游戏已经算不上是博弈游戏了,只能说是借用了一点博弈论的背景,其本质还是一个益智推理游戏。原因是:我已经把8种人物的特点都提前告诉你了(当然如果你假装不知道,或许还能和博弈搭点边)!所以要想玩好这款游戏,你所需要做的,就是通过某些方法推断出正在和你对决的是究竟是哪一位人物,并做出应对这位人物时的最佳选择即可(这里要提醒大家,游戏是定死的,而实际生活是复杂的,这款游戏中有一些固定的试探方式或是获益方式在生活中是绝对不可取的,请大家务必牢记,不要做出傻事)。其次,每一位角色出现两次的玩法是我经过深思熟虑后最终决定的。起初,我只让每位角色出现一次,这将导致一个问题,就是多数情况下,一直合作就是最优选择,因为有时试探出一个角色是谁是有一定代价的,而每位角色只出现一次,就意味着就算你推出了这位角色是谁,也没有太大的价值。此外,胡乱来的存在也让游戏的随机性增大,因而很难评定最终成绩的好坏。但如果让每位角色都出现两次,情况就不一样了,你可以尽可能在他们第一次出现时就摸清楚他们的底细,从而在他们第二次出现时,可以直接做出更好的选择,并且也可以一定程度上减弱胡乱来的影响,这样最终成绩就更能反应出推理能力了。此外,为了避免屏幕中内容过多,和每位人物博弈完一轮游戏之后就会刷新屏幕,这导致我们无法回看之前的对局信息,因而这在一定程度上也考验了玩家的记忆力。不过由于这款游戏的重点不在记忆,所以我还是认可大家在游戏过程中做一点笔记的。
说了这么多,大家会不会觉得这款游戏又复杂又困难呢?其实并不然,虽然这款游戏看上去复杂,还有很长的背景,但实际上推理的难度远远没有猜数字大。如果大家能把应对8种人物的策略进行一个全面的分析的话,是可以掌握一个基本稳定的套路的。嘿嘿,天机不可泄露,具体的我就不多说啦,请大家自行体会吧。
8.短文速打
这是一款比拼键盘打字速度的游戏。事实上,把这款游戏算进智力小游戏合集有些牵强,因为我也不清楚打字是否考验智力,可能还是熟练度的重要性更高一些吧。不过我觉得设计这样一个打字游戏会很有趣,所以还是把它归入了合集中。之所以会想到设计这样一款打字游戏,其实是受到了一款叫做《海底寻宝》的宝开游戏的启发。海底寻宝的核心玩法同样是打字,而且其中有一个教程模式就是专门用来给玩家练习打字的。我的好友小古比鱼曾写日志详细介绍过海底寻宝教程模式与练习打字的经历,同时还拍过教程模式每一关的视频。看到小古比鱼练习打字的卓越成果,我也有点心动了。于是,就在前不久,我也开始尝试游玩海底寻宝的教程模式,练习规范打字姿势。当我练过教程模式的所有课程后,想到今后可能要反复练习同样的课程,我觉得这可能会有些无聊,便突发奇想,要是我能编程将教程模式的玩法复刻下来,再导入我想要练习的文本,不就可以练习更多的文本了吗?这也便是我设计这个程序的由来。毕竟,我们学编程不单单是为了考试,更是要将这门技术运用在生活中,为我们制造便利的嘛!
然而,理想很丰满,现实很骨感。先前的许多游戏,玩法都很简单,因而只要抓住这个基本玩法,就可以一帆风顺地将代码写出来。而在这款游戏中,为了能够重现海底寻宝游戏中的种种设计,有许多细节问题需要解决。这也让我深刻体会到了宝开公司的游戏简单友好的背后,一定是制作者们花了许多心血实现的。海底寻宝中,游戏会实时判断我们是否打错,一旦打错,在将这个字符正确打对之前是不能跳过这个字符继续往后打的,因此,如果要实时反馈正确与否,必须每输入一个字符就判断一次。然而,问题远远没有那么简单。由于程序运行过程中,我们的输入也都会显示在屏幕上,当打字出现错误时,如果不经过处理,错误的字符会永远停留在原来的位置,这显然不合理也不美观,因而当出现错误时,必须输出退格键,不断将错误位清除,直到正确为止。更麻烦的是,运行过程中,在某些情况下,光标(打字的位置)可以通过方向键,TAB键等方式移动,在移动后的位置输入显然也会导致一定的混乱,因而必须通过各种方式让这些移动光标的方法失效。由于我没有学过类似的操作,只好在网上搜索,不断尝试各种方法,才最终利用SetConsoleCursorPosition函数解决了问题。此外,原游戏中还有这样的设定,一个单词不会被分开到一行的末尾和下一行的开头,并且一行中的最后一个单词与下一行的第一个单词之间无需打空格(但打了也不算错),然而由于我们的程序的运行窗口可以拖动,也就意味着一行中显示的字符数量是可以随意调节的,这不可避免地会导致在很多情况下造成部分单词被分割到一行的末尾和下一行的开头,而换行时无需打空格的功能就更是无从谈起了。因此,我实在找不到有效的办法可以实现上述两种功能,这也算是一个比较大的缺憾吧。此外,还存在字体过小,界面看起来远远不如海底寻宝美观等问题,都十分棘手,使我无能为力,因此这款游戏最终的实现效果并不十分理想。不过不管怎样,经过各种修修补补,我已经尽力实现所有我能做到的效果了,尽管并不十分完美,但我已经感到知足了。有趣的是,海底寻宝中当我们打字出现错误时会响出一个音效,而在我的程序中,我使用了响铃字符来模拟这样的效果!虽然音效完全不同,但至少能够体现出我真的是在尽力地去模仿,哈哈!
海底寻宝的教程模式的每一课打完后都有三项统计数据,WPM、Accuracy、AWPM。WPM表示每分钟所打的单词数,Accuracy代表正确率,AWPM代表将错误数量考虑在内计算得出的修正后的WPM。然而,由于游戏中并没有给出关于这三个数据的准确计算方法,因而如何精确复刻这三项数据的计算是我遇到的又一大问题。这个问题的主要困难在于,WPM和AWPM中的Words(单词)的数量究竟是如何衡量的?是以确确实实的单词数来衡量,还是用总的字符数除以英语单词的平均长度(某个常量)来衡量?这两种方法各有优缺点,前者容易理解,但因为单词长短不一,对于不同的文章,出现的单词的平均长度可能有较大差异,此外也较难将一些数字,标点符号等非单词内容包括进来考虑,因而采用这种方式来评判可能不太公平。第二种评判方式则误差更小一些,但这个常量的取值比较难以确定。如果不考虑复刻,仅考虑游戏本身,理论上这个值取成多少都无所谓,不会影响相对结果,但如果想要让我的这款小游戏中的一些成绩和海底寻宝中的一些成绩有可比性,这个值的准确选取就很重要了。经过再三考虑,我决定采取第二种方法,通过小古比鱼的视频收集数据,最终确定了这个常数的近似值为5.1。不过经过实测发现,在我的小游戏中,我的平均AWPM似乎比海底寻宝中的要低一些,不知是由于不熟悉文本,还是由于观感不舒适而影响发挥,又或者是由于这个数值仍然不准确……我暂时还没有改动这个数值,打算以后再多测试几次,如果仍发现存在问题的话,我会考虑对其进行修改。还有一个小问题是AWPM的计算方法,如何让错误数量对WPM进行修正呢?朴素的想法是,把总字符数扣去错误的数量作为实际的字符数来计算。经测试,这样的效果好像和海底寻宝中的结果差不多,因此为了方便起见,我这里也确实就使用了这样的简单方法来计算。
最后,回归到我们最初的目标,设计这个程序的意图是想要使用海底寻宝的教程模式的玩法来练习更多的文本,那么,加入什么文本进去呢?想来想去,我竟然又想到了一款宝开游戏:怪怪水族箱!玩过怪怪水族箱的朋友都知道,怪怪水族箱中有33个关于宠物或怪物的小故事,大多都很有意思,而且其中也包含了一些数字还有特殊符号等字符,通过打这些小故事来巩固我们的打字水平再好不过了!为了熟悉这些故事,同时也是为了锻炼自己的打字技术,我并没有复制故事的原文,而是看着小古比鱼曾经发布过的朗读怪怪水族箱33个英语小故事的视频,将这些故事老老实实地全部手打了一遍,同时还修正了一些错误。考虑到33个小故事加起来的内容太多,让玩家每次游玩时都全部打一遍并不现实,因而我的程序设计成每次游戏时都随机生成5个故事(总文本量和海底寻宝教程模式最长的一课差不多),每打完一个故事,就会显示当前的WPM,AWPM和Accuracy,同时玩家也可以休息一下,再继续打下一个故事,这样的话任务量就不会太大了。
9.脑力之王
本游戏考验综合能力。这款游戏可以理解成是前8个游戏的合集。其玩法就是,玩家要连续游玩之前提到的8个游戏,每玩完一个游戏,系统就会根据成绩评定一个分数,最终以8款游戏的总分作为最终成绩。这个游戏无疑是对玩家综合能力的大考验,只有对前8款游戏有充分的理解和熟练度,才能在脑力之王的比拼中获得一个好成绩。
由于连续游玩8个游戏需要一定精力和时间,因此我特地设计了一个存档系统。玩家在玩完任意一关后都可以选择保存并退出,下次开始游戏时仍旧可以继续上一次的进度。关于存档方面,在下一个部分中会展开细讲。
那么,每个游戏的分数具体是如何评判的呢?首先,我们列举一下每一款游戏的题量与评价指标。
加减速算——共20题。评价指标:正确数与用时
乘法估值——共10题。评价指标:正确数与用时
数字破译——共3轮。评价指标:三轮游戏的剩余次数之和
火眼金睛——共10题。评价指标:总得分与用时
过目不忘——共25个数字。评价指标:正确数与用时
勇者对决——共5轮。评价指标:胜利次数与用时
信任进化——共8个角色,各出现两次。评价指标:金币数
短文速打——共5篇短文。评价指标:AWPM(WPM与Accuracy也会统计,但不作为评价指标)
对于只有一项评价指标(记为R)的游戏(数字破译、信任进化与短文速打),我会对这个指标设定一个理论上限,记为MAX,如果玩家的成绩大于等于这个上限,即可得到满分2500分,成绩小于MAX的情况,则根据公式Score=2500*R/MAX来赋分(不难看出这是一个线性关系),结果取整。这里MAX的取值一般是一个较为理想的成绩。具体而言,数字破译的MAX为14(剩余次数),信任进化的MAX为226(金币数),短文速打的MAX为75(AWPM)。说实话,这些理想成绩,我目前几乎是达不到的,有些甚至看似是高不可攀的,我想对大多玩家应该也会是这样。这样设计的目的,也是为了激励玩家不断突破自己,挑战极限。为了让大家看得更直观,这里以短文速打为例,给出其得分与评价指标AWPM的关系图像(使用MATLAB绘制)。
对于具有正确数量(记为R,在火眼金睛中应理解为总得分,在勇者对决中应理解为胜利次数)与用时(记为T)两个评价指标的游戏,正确数量与用时都是总分的影响因素。由于这些游戏都没有什么运气因素,只要实力足够就可以全部正确,因此正确数量的理论上限也就是全部正确,记为MAX。在分数评定中,将按照公式Score=2000*R/MAX+500*min(exp((-a)*(T-T0)),1)来赋分,其中exp(x)是以自然对数e为底的指数函数,min(a,b)是取a,b中的较小者,a>0和T0>0都是参数,在不同游戏中取值不同。这个表达式看起来比较复杂,是关于R和T的二元函数,但其含义不难理解。其第一项和正确数量R有关,和只有一项评价指标的游戏的赋分公式十分相似,只是满分变成了2000;第二项和用时T有关,参数T0的含义是这款游戏的理想用时,当T≤T0时,这一项将取到最大值500(因此两项合起来的最大值还是2500),当T>T0时,这一项的数值将呈指数级下降,参数a用来调节下降速度(如果不加调节的话,exp(-x)的下降速度是非常快的,x=ln2≈0.693时就会下降到x=0时的一半)。具体而言,加减速算的a为0.02,T0为60;乘法估值的a为0.015,T0为80;火眼金睛的a为0.02,T0为60;过目不忘的a为0.01,T0为180;勇者对决的a为1.5,T0为1.5。从这个计算公式可以看出,正确数的权重相比用时还是要高一些的(这也是我的个人理念),因此,如果想要追求高分,还是要首先保证尽可能高的正确率,其次再考虑加快速度。同样地,理想用时T0也往往是我目前无法达到的,其用意也就不言而喻了。同样,为了让大家看得更直观,这里以加减速算为例,给出其得分与正确数和用时的关系图像(注意实际上正确数的轴上只能取离散点)。
可以想到,脑力之王得分的理论上限为2500*8=20000分,但由于每个游戏的满分都很难达到,要真正达到这个分数就更是难如登天了,或许只有真正的脑力达人才能做到吧!事实上,我认为总分能够突破15000就已经很不错了。目前我的最高分是15798,大家如果感兴趣也可以来尝试挑战一下。
10.主程序
在主程序中,玩家可以自由选择并游玩先前提到的9个游戏。我原本以为,在之前9个游戏已经设计好的情况下,只需把它们合并到一个工程文件中,在主函数中调用这些程序,就可以轻松完成这一任务。然而,事实上,主程序却是耗费我最多时间和精力的一个环节。一方面可能是由于我不单单想要把游戏合并,还想要加入一些其他的功能,但我认为更主要的一个原因是:没有做好足够的规划。之前9个游戏,我都是把它们当成单独的程序来考虑的,没有很好的可维护性,导致在合并和实现新功能的过程中,每个程序都要删删补补。这虽然这没有什么技术困难,但却十分消耗时间。因此,以后编程时,还是要多注意一些算法书写规范。在这学期我所上的数据结构课程中,我们的老师就提到了一些规范:如变量名、函数名等应见名知意,应添加必要的注释,以及应采用模块化设计方法,还有抽象的设计方法等等,这些都可以增加代码的可读性和可维护性。
那么,主程序中除了可以游玩9个游戏之外,还有什么额外的设计呢?首先,热爱挑战的玩家一定想要自己的分数能够被记录下来,不断尝试刷新记录,因此,高分榜的存在就很有必要了。于是,我为每一款游戏都设计了高分榜(每一个游戏的高分榜都有5个席位),并且在玩任意一款游戏的过程中(也包括在脑力之王游戏中玩其余8个小游戏时),都会根据最终成绩来判断是否更新高分榜。对于有正确数量和用时两项评价指标的游戏,在排名时永远是正确数量高者在前,当正确数量相同时,再比较用时。
另外一个功能也是十分有必要的。由于每次关闭程序后,运行过程中产生的数据都会丢失,因而如果不做特别的设计,即使有了高分榜,也只是一次性的,也即关闭游戏后再打开,之前的记录就全部消失了,这无疑很不好。因此,十分有必要设计一个存档系统。那么,该如何实现呢?我很快想到,这一定是需要在程序运行过程中,把一些数据自动保存到一个文件中,然后下次运行时再自动读取文件中的数据,这样就可以继承上一次的数据继续游戏了。尽管我先前并没有学习过C++读取和写入文件的操作,但由于我对实现这个功能的流程比较清楚,因而,在查阅了有关文件读写的资料后,没花多久,我就成功设计出了存档的功能!在一遍遍测试发现确实能够实现后,我还是感到很有成就感的。之前我自己玩其他游戏的过程中,总是觉得这些游戏中像是高分榜,还有自动保存之类的功能很高大上,似乎遥不可及,但在我仔细考虑并亲手尝试过后,才发现也并没有那么复杂。看到高分榜和存档功能全都实现之后,我感觉到,这至少有点像是一个成型的游戏了!能够迈出这样一步,足以让我十分高兴了!
事实上,为了使游戏更加完备,在存档系统中,我还加入了一个小的加密系统,不妨在此也和大家分享一下。如果玩家修改了存档文件中的数据再打开游戏,有了这一加密系统,游戏会识别出玩家的这一举动并禁止玩家进行游戏,直到存档文件恢复正常。这看似很神奇,其实实现的方法很简单。事实上,在保存存档数据时,除了将一些存档数据写入文件之外,我还会再额外写入一个校验码(类似身份证号的最后一位的功能,也有点类似通信中的纠错码,不过其只能验错,而不能纠正错误),这个校验码是以所有的存档数据为自变量,按照一定函数关系生成的。每次程序运行时,系统都会读取存档数据,并按照这个函数计算出一个值,与校验码进行比较,如果误差过大(设置一定误差容量是为了保险起见,防止因计算误差而导致误判),就意味着玩家一定修改了存档。至于这个校验码究竟是按照怎样的函数关系生成的呢?这当然是不能告诉你们的啦!事实上,我自己也记不住我是怎么构造的了,反正就是复杂到谁都不可能猜到就对了。有趣的是,我的好友真强悍也曾在他的一个作品SAVE ZQH中运用过类似的防作弊系统。我之所以会想到设计这样一个存档系统,其实不是因为我对玩家不信任,而是受到了真强悍的启发,也想要动手尝试实现一下这种技术而已。
其实我还曾经考虑过让程序保存多名玩家的存档,并且在高分榜中也能显示不同玩家的名字。这在技术上应该也是不难做到的,然而由于时间有限,最终这个想法并没有实现,算是一个缺憾吧。
到此为止,这个程序的全部内容就介绍完毕了,融合了多款游戏,涉及了多个学科,大家看完会不会觉得信息量有点大呢?哈哈,说实话,我也是费了好大的功夫才将所有内容整理清楚,并向大家展示的。这个程序和这篇日志也可以算是我这几个月来努力的成果了,对此,我还是感到十分自豪的。不过,我也认识到,这个程序看似内容纷繁复杂,但在设计上却并没有太高的技术含量。事实上,我仅仅是利用了C++前几节课教的最基础的语法知识,加上网上搜索的一点点特殊功能的实现方法(如控制光标、文件读写等),就完成了这一作品。还可以实话和大家说,代码中有不少地方由于我没有想到更好的方式来实现功能,就采取了一些笨办法(甚至是枚举)来实现,因此,我也就不打算公开源代码献丑了,相信各位编程达人们如果花上一点时间,一定有能力比我完成得更快更好。
用C++编写的游戏可以分成很多等级,像这种只能在控制台中运行的游戏,就是最基础的控制台游戏。而我这部作品,就设计难度而言,在控制台游戏中应该也是排不上号的。高级一点的控制台游戏应该有贪吃蛇、俄罗斯方块等经典游戏。虽然我还是有自信认为在时间充足的情况下,我有能力复刻出这些游戏,但几乎可以肯定,这会比设计我的这一游戏要难。因此,这次的尝试仅仅是刚刚起步,倘若真要从事游戏设计,还有很长的路要走。目前我还没有这样的打算,不过,多尝试一些新东西总是好的。兴趣是最好的老师,以感兴趣的游戏作为引导来练习编程,既有趣,又能锻炼自己的编程能力。大家如果学习过编程,不妨也可以尝试选择一个自己喜欢的游戏来复刻一下,一定会很有意思的!
这篇文章到这里也就接近尾声了,感谢大家的仔细阅读,感兴趣的朋友可以尝试一下我的这款游戏(下载地址:https://www.mlaalm.ys168.com/ 蓝天白云小游戏集目录中)),看看你能够创下什么记录,欢迎大家和我分享。如果大家在程序运行过程中发现有什么BUG的话也可以向我反馈,我会进行更新。下一步,我打算在明年春季开始学习Python,如果今后在学习和实践的过程中有什么有趣的经历的话,我也有可能会继续写文章和大家分享,敬请期待!再说几句题外话吧。我预计将在明年1月1日开始继续更新视频,不过由于那时还未放寒假,视频的更新会很少,等到正式开始放寒假(大约1月24日),会开始正式更新。至于更新的内容,可能组成结构和去年寒假差不多。首先一定会继续更新魔塔永不复还与光明崎岖的视频流程,也会按照惯例带来文字类游戏的实况流程,还有一些其他的视频系列就先不透露了,另外也会带来几部精彩的非专辑视频,大家也可以期待一下。
最后,这不平凡的2020年就快要过去了,我们即将迎来崭新的2021年,祝愿在新的一年里,大家都能健康快乐、学有所成!