正如课程安排中的第一周内容所说,Project0提供了一次很有意义的项目练手机会。留给练习的任务是2048小游戏的逻辑设计,在课程刚起步阶段,为达这一目标需要克服许多畏难心理,如:畏惧陌生语法、畏惧繁多文件、畏惧各种class的定义、畏惧陌生IDE的配置。Project0的引导很细心地让我几乎不得不直面这些畏难心理。
引导首先设置了编写三个Test方法的小练习,对标工程中的Test项目,跑过Test的逻辑十分简单,练习的价值主要就在于努力读懂并使用工程中许许多多的class定义——这可以看作是一次对架构的学习。工程文件的核心class为Board、Tile、Side,其中Tile的定义对于初学面向对象语言的我来说十分晦涩难懂。最大的困惑是,在一个class的定义里引入该class的实例作为class成员,再加上class中声明的成员变量一般还附有许多陌生的modifier,使得靠自己入门仅有的语法知识来反推如此行为的意义变得十分困难。project0最有价值的地方我觉得就在这里,正如Josh Hug自己所说,it's ok for you to be confused and not able to figure out everything in the project。保持困惑能激发人的好奇心也能使人劝退,对于学习而言,关键在于困惑的程度。每当我放弃思考困惑点,继续聚焦于工程的任务时,我发现自己依然能够推进project的进度,这种成就感总是能打消不少困惑带给人的受挫情绪,使我一直没有放弃对困惑的思考,而后来的课程内容证明,这种思考是很有意义的——class成员的声明并不等于调用;Java在实例化class时,赋给instance的值为引用变量(reference variable),代表该instance的地址。project0之后就是对链表的编写学习,而编写链表的核心就在于每实例化一个class,就附带有下一个实例的地址。这些困惑,再往后便让我对递归思想有了思考的基础——很早接触编程就已听说甚至使用过递归,但在project0中的思考才使我真正感受到对递归的慢慢掌握。
完成了三个Test方法之后,就是对游戏核心逻辑的设计了,这是针对本次目标而言真正逻辑思考的难点。如何知道每次移动时,哪些tile该动,又该移动到哪个位置?这是需要解决的核心逻辑问题。在之前写Test方法的过程中,我熟悉了使用横竖两个方向遍历的方式来获取board中的每一个tile,根据遍历的顺序,首先提取board中的一列,然后按行提取特定的tile。project文件中的class Side就是围绕这一遍历方式而设计的巧妙办法,使得每一个方向的移动都可以看成一列tile向上的移动。那么只需在每一列的循环之中,判断当前循环所选tile的上部是否存在空档,就可完成存在空档情况下的移动操作。除了空档之外,移动判断还有是否融合,但其实核心逻辑跟空档移动类似,只是再多了一次循环来使得融合之外的tile进行填补移动。