5x5 矩阵有讲究啊,如果是 4x4 会有点麻烦
-------------12.31. 更新分割线----------- 试了一下,累计时间已经超过两个小时了,目前还有 bug,好泄气
一些解题帮助:
这个练习题有满多的复杂性,主要呈现在两个方面:1. 如何记载和跟踪游戏状态,以及带来的怎么样的面向对象的数据封装比较合适?2. 如何把一个大的题目化整为零,来计划一步步的实现过程?其他在具体的算法和编程方面并不是很难。
在第一个方面,可以首先在全局上检查可能需要追踪的游戏状态:
- 两个玩家(电脑/人) -两个棋盘及其方格 - 游戏状态:现在该哪个玩家打;是否有人胜出 - 所有方格的状态(被打击但无船;被打击打到船;未被打击) - 所有舰船的方位和朝向 - 舰船的状态(未被击沉/被击沉) -朝每个棋盘发射过的所有炮弹
在面向对象编程的框世里,一般来讲是把名词抽出来作为对象的,比如说这里面的 玩家,舰船,炮弹,棋盘,方格,游戏。但如果从这个角度入手,往往在一开始的时候就面对着如何设计对象层级及对象间交互的方式,是比较困难的。有些同学会不太多考虑的选择几个概念来封装成类,代码写起来再说,但其实不理想的封装会带来后面程序复杂度的大幅度提高。
可以考虑这样一个角度:如果检查所有的状态,会发现这些游戏状态并不是互相独立的 - 而有些状态是可以从其他的状态计算出来的 - 比如说所有方格的状态可以由舰船位置和所有炮弹的位置计算出来。在选择类/对象的时候,尽量选择基本的,相互独立的状态,把它们封装,由他们再计算出其他的状态。
还有一个角度,是优先考虑再问题描述中高频出现的概念。在这个问题描述中,“船”的概念非常频繁的出现,这说明在这个题目里,有很多的算法(步骤)和逻辑对”船“这个概念是有依赖的。所以把”船“抽象出来作为一个基本砌块是有优势的。而如果不固化这个概念,势必在代码中到处计算和反推这个概念,增加不必要的复杂度。
在选择出基本的几个状态及类封装后,可以回头把需求中的所有逻辑和其他状态 向选择的基本状态沉积。这样程序的大体框架就有了。
下次讲 化整为零 解决问题的方法。
想了一下,不应该怕丢人,代码在 https://github.com/fsword/ship-game
总结一下试验的收获:
在游戏流程控制上,感觉是你是在用类似即时战略游戏的思想来实现回合制的游戏 :) 事件驱动和绑定玩的蛮高端,对这个题目是牛刀了,因为本身游戏的流程可以都放在 game loop 里面的,而且总是 玩家 -> 电脑 -> 重新画屏。你的实现方法如果是很多玩家同时乱打倒是很合适的。
在跟踪状态和建模上面,用每个 shot 引起从 TeamController 到 Team 到 Matrix 到 Ship 的状态改变,以及 MatrixDelegator 对 Matrix 本身的加强,感觉对象间太多依赖,交互太多;从另一个角度看,这些对象除了 Ship 外都比较浅,执行形式以 delegation / pass through 为主(尤其是 shot_at 的 delegations ), 可以考虑把一些对象变化成类似 transformation 的函数。在代码从面上,你大多数的方法是以 command / delegation 为主,如果多考虑用 数据进 /数据出的函数,会逼迫你简化对状态的代表方式,从而减少总体复杂度。