持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情。
背景
兄弟们,之前我开发了支持联机对战的五子棋、斗地主、UNO。在大家的呼吁之下,我准备开发「象棋」啦!
😄 不出意外,国庆假期,联机象棋就能跟大家见面了!
之前的进展:
继续给大家同步进展:今天,设计了象棋历史记录的保存方案,尽可能降低了空间的占用。
基于该方案,我们可以实现悔棋操作,非常实用。
思考
我之前开发的五子棋,是支持悔棋的,并且可以无限悔棋直到第一步。
但是象棋不一样。象棋的步骤是无限的。随着步数增多,历史记录的空间占用一定是线性增长的,并且永不止境。所以我只会保存最近1000步(或者9999步等)。
这里罗列一些方案:
方案 | 优点 | 缺点 |
---|---|---|
记录每次操作后,当前棋局所有棋子的位置 | 比较无脑,开发快 | 占用空间大 |
从初始局面开始,顺序记录用户操作的棋子、移动后该棋子的位置 | 占用空间很小 | 本方案不适用,因为每一次记录都依赖上一步的局面(不然不知道吃了谁、也不知道移动前的位置) |
从现状局面开始,逆序记录用户操作的棋子、移动前该棋子的位置、吃了谁 | 占用空间相对小 |
我选了第三个方案,因为它是逆序记录,可以从当前局面非常快的推演出悔棋后的局面。
数据结构
确定了方案:从现状局面开始,逆序记录用户操作的棋子、移动前该棋子的位置、吃了谁。
还需要决策,具体怎么存。
初步的方案
- 棋子一共有32个,标识一个棋子需要用5个二进制位。但是因为红黑是轮流进行的,所以标识棋子可以缩短到16个数字,即4个二进制位。
- 而标识吃掉了谁(也可能没吃掉),需要17个数字,只能用5个二进制位了。
- 棋子移动前的位置一共有90个,需要7位二进制来存储。
共计每一步操作需要4+5+7=16个二进制位。
改进:优化吃掉了谁
其实吃掉将帅后 游戏就结束了。将帅是否被吃掉,可以通过当前棋盘状态来看。因此我们可以优化「吃掉了谁」这个变量:把0
改为没吃掉任何人或吃掉了将帅。
这样每一步操作需要4+4+7=15个二进制位。
改进:优化移动前的位置
我还是不够满意,因为每个棋子移动的范围是有限的:
- 将帅最多有4个可移动范围。只需要2位。
- 士最多有4个可移动范围。只需要2位。
- 象最多有4个可移动范围。只需要2位。
- 兵最多有3个可移动范围。只需要2位。
- 马最多有8个可移动范围。只需要3位。
- 车最多有17个可移动范围。只需要5位。
- 炮最多有17个可移动范围。只需要5位。
而我们知道了用户操作的棋子是谁,就知道了它的可移动范围了。
这样每一步操作需要4+4+2=10至4+4+5=13个二进制位。
改进:优化吃掉了谁
还可以进一步压缩。因为大多数移动,都是没吃掉任何棋子。我们可以用一个位标识用户是否吃掉了棋子。如果吃掉了,再用4位来标识吃掉了谁。如果没吃掉,就不需要这4位了。
这样每一步操作需要4+1+2=7至4+1+4+5=14个二进制位。
写在最后
我是HullQin,独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费无广告。还独立开发了《合成大西瓜重制版》。还开发了《Dice Crush》参加Game Jam 2022。喜欢可以关注我噢~我有空了会分享做游戏的相关技术,会在这2个专栏里分享:《教你做小游戏》、《极致用户体验》。