博客近两天略惨淡啊,我会先在博客上不定时的更新,毕竟是想把博客做成自己的主要平台嘛,谢谢支持啦!希望大家能猛戳http://www.richinmemory.com/
三、桌面山寨版2048—优化篇
当这所有的初步编码都实现之后,我长舒了一口气并且自己玩了1个 小时,虽然整个尤其并没有什么高深的编程技巧,但是真的做到把游戏程序拷贝到任何一个电脑上大家都能玩的地步还是需要花一点精力的。在短暂的享受一下成就 感之后,又回到代码的界面,看到处理按键逻辑的那一部分,总有一种感觉,感觉如果半天没看这段代码,我可能就再也看不懂了。看着这一个个的循环总感觉代码 在张力上缺乏点什么,越看越觉得就像自己脸上糊了一脸的泥,所以,我决定,一定要找点什么来优化优化。
我的第一反应每次没必要循环那么多,就拿“下”这个方向键来说,没必要从最后一行开始遍历,因为最后一行没有下一行,也就根本不可能发生合并操作。但是一个一共只循环16次的循环变成12次,对于现在动不动就4核的计算机来说,根本就不值一提,这种优化只能是书上的优化。
回到现实中来,大大优化一个代码无非从规范代 码,数据结构,算法三个方面考虑,不要小看第一点,工作也快一年了,我觉得在实际生产中,绝对第一点占了最大的比例。因为我山寨这个小游戏的行为绝逼只能 算是小作坊行为,所以规范代码我就不想了,剩下的两个,明显考虑使用一个更合适快捷的数据结构比想一个更加牛逼的算法更方便,毕竟人本性都是懒惰的,所以 我尝试能不能找到一个更加合适的数据结构。
由于这个游戏是一个4×4的 方格,所以我第一个想到是用一个图,也只是想想而已,我只是想挑战一下自己的编程习惯,还没想要挑战自己的智商。剩下来继续搜寻,树,哈希表貌似和这很难 一下子发生联想,于是我就试试能不能套用下堆栈啊,队列啊,这一套,我还真想出了个办法。完整的灵感迸发的过程是这样的:我看着这一个4×4的 大方块,看看自己的循环,“上下”这两个方向都是按照行进行遍历的,“左右”都是按照列进行遍历的,如果我反过来一下,“上下”按照列,“左右”按照行, 因为“上下”合并关系都是在行于行之间发生,一次处理一列貌似是更加贴近人自然思维的方式。比如“下”,从最底部开始,一个数字一个数字进行处理,然后将 合并的结果再一个数字一个数字写回原来的区域,从最后一行往第一行遍历,也从最后一行往第一行处理,写回。这不是活脱脱一个FIFO的过程吗?于是很自然的就想到队列这个犀利的数据结构。而且在实施时,更加发现,只需要一个容量为2的队列就可以完美的实现这个游戏的逻辑。
有了这个开头,后面的就简单了。还是以“下”这个方向为例,从最后一行最后一列开始,假设是3,3),如果这个数字不是空,那么将这个数字入队,如果是空,则跳过。接着遍历上一行(2,3), 如果是空,则跳过,接着遍历上一行。如果是数字,则入队,然后判断是否和前面的一个数字是否相同,如果相同,则更新队列中前一个数字,并且填入相应的区 域,同时两个相关的数字都出列。这样不仅可以正确的合并操作,并且可以有效的避免一次合并好几个数字的现象。然后以此类推就可以完成全部的操作。这样叙述 有点逻辑混乱,我举两个例子来尝试解释清楚。
比如一列数字是2空28,首先,8入队,接着2入队,这两个数字不相同,所以将8出队,填入最后一行,下一个是空,不需要处理,下面入队是2,和队中相邻元素是一样的,则更新相邻元素为4,出列,填入相应的格子,循环结束,操作终止。
再举个例子,比如一列数字是2288,那么8首先入队,接着8入队,发现相邻两个元素相同,所以更新数字同时两个元素出队。接着入队2和2,同样重复上面的操作,循环终止,操作结束。而且这样的处理过程绝对不会发生一下子合并好几块的现象。
将上面的逻辑实现成代码很简单,特别是我在使用的时候直接使用的STL里面的queue容器,连队列的实现都省了。在循环中,使用一个标识符记录当前未被填入的最后一行的行号,在每次出队的时候就可以将数字正确的更新到正确的位置。
如果将队列换成堆栈,一样能够实现上面的逻辑。
这个优化的版本代码真正改动代码部分的技术到没有什么,我觉得重要的是这个逻辑和最后处理的思路。所以,如果你需要完整的代码,请来我的博客http://www.richinmemory.com/ ,我的邮箱就在那儿,给我邮件吧。