如何高效存储棋局?

Cod*_*der 5 database compression algorithm encoding bit

在数据库中存储整个国际象棋游戏最节省空间的方法是什么?考虑到平均游戏长度为 50-70 步(1 步意味着 2 个玩家移动一次),我希望它需要少于 800 位。

棋子的初始位置可以存储在 6 位中,而移动可能需要 2-4 位。有什么方法可以存储比这个更少的东西吗?

tri*_*cot 10

您可以枚举给定位置的所有合法动作,并以商定的方式对它们进行排序(例如按起始方格,然后按目标方格,然后按升级件 - 如果涉及升级,...)。然后通过合法移动排序列表中的索引来识别每个移动。

找到的合法步数最多的(理论)位置有218 个合法步数。我们可以确信不存在超过 256 个合法动作的位置,因此 8 位足以编码单个动作。

采用这种编码,70 步的游戏将需要 560 位。

动态位数

然而很明显,在大多数位置,合法移动的数量更像是 40,而不是 218,因此我们可以让下一个编码移动的位数动态地取决于可用的合法移动的数量。

由于起始位置只有 20 个棋步,因此第一个白棋棋步将仅用 5 位进行编码;第一个黑棋也是如此。随着游戏的继续,很快就会出现一个位置的合法步数超过 32 步,因此将使用 6 位。例如,之后

1. e3 e5
2. Qg4 d6
Run Code Online (Sandbox Code Playgroud)

...白棋有 46 种合法的走法,因此他们的走法将使用 6 位进行编码。我们已经保存了 3 x 4 = 12 位(相比之下每次移动 8 位)来编码前四个移动。

在编码时,算法会首先检查有多少个合法的棋步,然后使用相应的位数对下一个棋步进行编码。解码器还可以知道合法移动的数量,然后从编码流中消耗该数量的比特。

我不知道最坏情况下的 70 步游戏需要多少位数(在合理的时间内无法计算),但它将远低于 500 位。

最小化合理的游戏

上述导出的限制适用于任何游戏,甚至是玩家做出最差动作的游戏。但是,如果您想专注于合理的游戏,您可以进一步优化内存占用:

使用确定性国际象棋引擎为每个合法的动作生成一个分数,并使用该分数作为实际执行该动作的概率。重要的是,在相同的游戏状态下,相同的动作总是会产生相同的分数。使用霍夫曼编码对移动进行相应的编码。这意味着好的动作比坏的动作需要更少的比特。比如说,如果能擒住女王,甚至可以成为一招。愚蠢的举动将需要比平均更多的比特,甚至可能超过 8 位(当有很多合法的举动并且它们包括非常好的和非常糟糕的举动时)。一个 70 步棋的游戏,几乎所有棋步都不好,可能会比非霍夫曼编码算法占用更多的比特,但合理的游戏会使用更少的比特。

  • 甚至可以进行算术编码——根据某些确定性国际象棋引擎对每个合法动作的评估来估计概率。熟练玩家的游戏可能会在 100 位以下。 (2认同)