今天上午,小古比鱼照例打开电脑,玩起了锤锤小矮人马拉松模式的游戏。玩着玩着,发现屏幕左上角的分数居然变成了负数,如图所示:
可以看到,小古比鱼玩锤锤小矮人的马拉松模式,已经玩到了31:26:00;在获得这次的时间奖励(943500×5)之前,游戏分数为2143984755,而在获得时间奖励之后,分数竟破天荒地变成了-2146265041!真是匪夷所思啊!大家一定会问:分数究竟为何会变成负数呢?事实上,其原因并不难理解——倘若大家对计算机方面的知识有一定了解,相信大家已经猜到了答案——数据溢出。没错,就是这么简单!
事实上,关于这次锤锤小矮人马拉松模式分数溢出变负的情况(以下简称“分数溢出事件”),小古比鱼未卜先知,早已料到了三分!其主要是缘于几年之前,小古比鱼在一次浏览网上有关宝石迷阵3禅意模式游戏的攻略之时,隐约记得当时有位网友曾经说过这样的话,他说:宝石迷阵3禅意模式的关卡数最多为32767,超过之后会出现问题;宝石迷阵3禅意模式的游戏分数上限为2147483647,超出之后会变成负数。因此,小古比鱼便想了,倘若那位网友所说的话当真无误,那么类比一下,锤锤小矮人马拉松模式的分数或许也是如此。果然,上午发生的“分数溢出事件”证实了小古比鱼的预测!也正是因为这个原因,在分数即将溢出之前,小古比鱼刻意备份了游戏存档,以便用截图的方式将这一历史性的时刻记录下来。然而,喜欢刨根问底的小古比鱼并不满足于“数据溢出”这样一个过于简单的解释,因此,在“分数溢出事件”发生之后,小古比鱼又上网查询了相关的资料,结合自己的思考,编写了一个C++程序,以对其中的道理进行揭秘。在向大家展示这个C++程序之前,小古比鱼想先为大家介绍一下相关的理论知识。
众所周知,C语言(包括C++)在编译时,会为程序中的每个int型(整型)变量分配4个字节,即32位二进制数;这32位二进制数的最高位为符号位,其余31位为数值位。由此可见,若用十六进制(补码形式)来表示,int型变量所能容纳的最大值为7FFFFFFF(即2^31-1,或十进制的2147483647),而int型变量所能容纳的最小值为80000000(即-2^31,或十进制的-2147483648)。因此,倘若一个int型变量的取值超出了上述范围,自然便会发生溢出。不难推测,在锤锤小矮人的游戏程序中,分数的存储采用的便是这样一个int型变量,故满足上述规则;宝石迷阵3禅意模式的分数亦是如此。更进一步,倘若那位网友所言不虚,据此可以推测,宝石迷阵3禅意模式的关卡数是一个short型(短整型)变量,其只占2个字节,故最大值为32767(即2^15-1)。以下便是小古比鱼所编的C++程序(名为“锤锤小矮人马拉松模式分数变负问题揭秘”),用于揭秘锤锤小矮人马拉松模式分数变负的问题:
C/C++整型上下限INT_MAX INT_MIN及其运算:https://blog.csdn.net/u012604810/article/details/80290706
INT_MAX和INT_MIN:https://blog.csdn.net/u010325193/article/details/80287777
C语言中提供了一些诸如“INT_MAX”、“SHRT_MIN”之类的符号常量,我们可以通过它们来获取相应的限值。如果大家看懂了小古比鱼所编的这一程序,想必对于这个问题,大家现在也一定和小古比鱼一样心知肚明了!小古比鱼认为,这样的数据溢出问题可能同样存在于毛毛球禅意模式的分数,甚至其他许多游戏当中,只不过,鉴于游戏本身的设定,要想在宝石迷阵3的禅意模式或毛毛球的禅意模式当中看到分数溢出的现象,恐怕并不是一件容易的事情!值得一提的是,不知大家是否记得,在巴士驾驶员游戏当中,当游戏驾驶得分超出9999之后会出现问题,游戏将只显示低四位数(即个位、十位、百位、千位),而不显示万位(及更高位的)数,其机理虽与此有异曲同工之处,却又并非完全一致,小古比鱼在此就不做过多的解释了,有兴趣的朋友可以自行研究一下,再与小古比鱼进行探讨。
大家可能会想:既然锤锤小矮人马拉松模式的分数出现了问题,我们如何才能获知自己当前的真实分数呢?不必担心,小古比鱼稍后编写的另一个C++程序(名为“锤锤小矮人马拉松模式真实分数计算”)可以帮助大家解决此问题:
该程序运用了以前小古比鱼编写C程序时便常用到的“__int64”类型,其相当于C++中的long long型(双长整型),每一变量占8个字节,即64位二进制数,借此来存储绝对值相当大的整数(-2^63~2^63-1)。该程序的原理是:每当游戏中出现一次分数溢出,其显示分数将比真实分数扣除4294967296(即2^32,或-INT_MAX×2),据此,只要我们知道了游戏截止到目前为止出现过多少次分数溢出的情况,便可通过计算得出游戏真实的分数。譬如,根据上图程序运行的结果,当产生1次分数溢出,且当前显示的分数为-2146265041时,其真实分数为2148702255,恰好等于2143984755+943500×5(参见本日志开头的两张游戏截图)。
有了这个程序,我们就可以随时通过游戏中所显示的分数得出真实分数了!但是,这终归是一项麻烦的工作,因为我们不可能边玩游戏边运行这个程序,否则我们根本无法很好地体验游戏;换句话说,游戏中的分数溢出问题,无疑会在一定程度上影响到我们游玩该游戏的热情,毕竟原本以为能够“永久”积累的分数,现在也变得不再“可持续”了。幸好,马拉松模式的游戏时间与金钱数对我们来讲还算是个安慰,至少二者在目前来看尚没有“溢出”的倾向。不过,小古比鱼想说的是:无论游戏本身的设定如何,也无论游戏在进行过程中出现什么样的状况,小古比鱼依然会继续玩下去,直到自己真的不想再玩的那一天!
以下是小古比鱼近期玩锤锤小矮人马拉松模式的部分游戏截图。目前小古比鱼在该模式下已玩了31:32:37,真实分数2158108458,金钱数218250。顺带一提,在金钱数收集到200000之后,小古比鱼开始尝试练习在游戏中有意不拾取掉落的金币,而只通过宝箱、小丑、金塔等方式积累金币,以此来“降低”游玩难度,同时也为夺取奖章室里的最后两枚奖章提前做一下准备。事实上,即便如此,由于小古比鱼现在很少进商店,因而收集金钱的速度与此前相比也并未减慢太多。
最后,敬请大家期待小古比鱼的下一部有关锤锤小矮人马拉松模式的高进度型视频,也敬请大家期待小古比鱼的下一篇编程日志!