这是我之前关于决定一手牌是否准备好的问题的后续。
麻将规则的知识会非常好,但是基于扑克或罗姆棋的背景也足以理解这个问题。
在麻将中,14 张牌(牌就像扑克牌中的牌)被排列成 4 组和一对。顺子(“123”)总是使用 3 张牌,不多也不少。一组相同类型(“111”)也正好由 3 个牌组成。这导致总和为 3 * 4 + 2 = 14 个图块。
有各种例外,例如 Kan 或十三孤儿,在这里不相关。颜色和值范围 (1-9) 对算法也不重要。
一手牌由 13 张牌组成,每次轮到我们时,我们都要选择新的牌,并且必须丢弃任何牌,所以我们留在 13 张牌上——除非我们可以使用新选的牌获胜。
可以安排形成 4 组和一对的手是“准备好的”。只需要交换 1 张牌的手被称为“tenpai”,或“1 from ready”。任何其他手都有一个shanten-number,表示需要交换多少张牌才能进入tenpai。因此,一手牌数为 1 的牌需要 1 张牌才能成为 1 牌(相应地需要 2 张牌)。一手牌数为 5 的牌需要 5 张牌才能成为十牌,以此类推。
我正在尝试计算一手牌的 shanten 数。在谷歌搜索了几个小时并阅读了关于这个主题的多篇文章和论文之后,这似乎是一个未解决的问题(除了蛮力方法)。我能找到的最接近的算法依赖于机会,即它无法 100% 地检测到正确的 shanten 编号。
规则
我将解释一下实际规则(简化),然后我的想法是如何解决这个任务。在麻将中,有 4 种颜色,3 种正常的颜色,就像纸牌游戏中一样(ace、heart、...),称为“man”、“pin”和“sou”。这些颜色各从 1 到 9,可用于形成直线以及同类组。第四种颜色被称为“荣誉”,只能用于同类组,但不能用于直道。七项荣誉将被称为“E、S、W、N、R、G、B”。
让我们看一个十牌手的例子:2p, 3p, 3p, 3p, 3p, 4p, 5m, 5m, 5m, W, W, W, E
。接下来我们选择一个E
. 这是一张完整的麻将手(准备好了),包括 2-4 针街(记住,针可用于顺子)、3 针三人组、5 人三人组、W 三人组和 E 对子。
将我们原来的手稍微改变为2p, 2p, 3p, 3p, 3p, 4p, 5m, 5m, 5m, W, W, W, E
,我们得到了 1-shanten 的一手牌,即它需要一个额外的牌才能成为十牌。在这种情况下,将 2p 换成 3p 会让我们回到tenpai,所以通过抽出 3p 和 E 我们赢了。
1p, 1p, 5p, 5p, 9p, 9p, E, E, E, S, S, W, W
是 2-shanten 中的一手牌。有 1 个完整的三胞胎和 5 对。我们最终需要一对,所以一旦我们选择了 1p、5p、9p、S 或 W 中的一对,我们需要丢弃其他一对。示例:我们选择一个 1 引脚并丢弃一个 W。这手牌现在在 1-shanten 中,看起来像这样:1p, 1p, 1p, 5p, 5p, 9p, 9p, E, E, E, S, S, W
。接下来,我们等待 5p、9p 或 S。假设我们选择 5p 并丢弃剩余的 W,我们得到1p, 1p, 1p, 5p, 5p, 5p, 9p, 9p, E, E, E, S, S
:这手牌是十牌,可以在 9 针或 S 上完成。
为避免更冗长地绘制此文本,您可以在wikipedia上阅读更多示例或使用 google 的各种搜索结果之一。不过,所有这些都更具技术性,所以我希望上面的描述就足够了。
算法
如前所述,我想计算一手牌的 shanten 数。我的想法是根据颜色将瓷砖分成 4 组。接下来,所有的牌都被分类到各自组内的集合中,我们最终在荣誉组中得到三联、对或单个牌,或者另外,在 3 个正常组中得到一串。已完成的集合被忽略。对数进行计数,最终数字递减(最后我们需要 1 对)。单个瓷砖被添加到这个数字。最后,我们将这个数字除以 2(因为每次我们选择一个能让我们更接近天牌的好牌,我们就可以去掉另一个不需要的牌)。
但是,我不能证明这个算法是正确的,而且我也很难为包含许多近距离瓷砖的困难组合并直道。每种想法都值得赞赏。我正在使用 .NET 进行开发,但也欢迎使用伪代码或任何可读语言。