【问题标题】:Algorithm to find streets and same kind in a hand寻找街道和同类的算法
【发布时间】:2013-04-10 17:28:59
【问题描述】:

这实际上是一个基于麻将的问题,但是基于 Romme 甚至扑克的背景也很容易理解。

在麻将中,14 张牌(牌就像扑克牌中的牌)被排列成 4 组和一对。一条街道(“123”)总是使用恰好 3 个瓷砖,不多也不少。一组相同类型(“111”)也正好由 3 个牌组成。这导致总和为 3 * 4 + 2 = 14 个图块。

有各种例外情况,例如 Kan 或十三孤儿,与此处无关。颜色和值范围 (1-9) 对算法也不重要。

我正在尝试确定是否可以按照上述方式排列一只手。由于某些原因,它不仅应该能够处理 14 个瓷砖,而且应该能够处理任意数量的瓷砖。 (下一步是找出需要交换多少牌才能完成一手牌。)

例子:

11122233344455 - 很简单,4 套一对。
12345555678999 - 123, 456, 789, 555, 99
11223378888999 - 123, 123, 789, 888, 99
11223344556789 - 无效牌

我目前尚未实施的想法是:对于每个图块,尝试制作 a) 一条街道 b) 一组 c) 一对。如果没有一个有效(或者会有 > 1 对),则返回上一个迭代并尝试下一个选项,或者,如果这是最高级别,则失败。否则,从剩余图块列表中删除已使用的图块并继续下一次迭代。

我相信这种方法行得通,而且速度也相当快(性能是“不错的奖励”),但我对您对此的看法很感兴趣。你能想到替代解决方案吗?这个或类似的东西已经存在了吗?

(不是作业,I'm learning to play Mahjong.

【问题讨论】:

  • 哦哦哦我知道了,我会用正则表达式!!11!
  • 有些人在遇到问题时会想“我知道,我会使用正则表达式”。现在他们有两个问题。~ Jamie Zawinski :)
  • 您最多可以拆分三组试图形成一条街道(或相反)。可以吗?
  • 说真的,我认为正则表达式在这里可能很有用。我手头没有语法,因为我很少使用它,但它应该很容易。至少对于不强调速度和可扩展性的“临时”解决方案而言。
  • @bel:是的,你可以拆散任何东西,只要你最终得到 4 套/街道和一对。哦,顺便说一句,街道上没有没有 1/9 环绕。

标签: algorithm poker mahjong


【解决方案1】:

一条街道和一个集合中的值之和可以除以3:

  • n + n + n = 3n
  • (n-1) + n + (n + 1) = 3n

因此,如果您将一手已解牌中的所有数字相加,您将得到一个 3N + 2M 形式的数字,其中 M 是该对中牌的值。对于 M 的每个值,除以三 (total % 3) 的余数是:

total % 3 = 0  -> M = {3,6,9}
total % 3 = 1  -> M = {2,5,8}
total % 3 = 2  -> M = {1,4,7}

因此,您不必测试九个可能的配对,只需根据简单的加法尝试三个即可。对于每个可能的对,删除具有该值的两个图块,然后继续算法的下一步以确定它是否可能。

一旦你有了这个,从最低的价值开始。如果具有该值的图块少于三个,则意味着它们必然是街道的第一个元素,因此删除该街道(如果因为缺少图块 n+1 或 n+2 而不能,则表示手无效)并移至下一个最小值。

如果至少有三个具有最低值的图块,则将它们作为一组移除(如果您问“如果它们是街道的一部分怎么办?”考虑如果它们是,那么还有三个图块 n+ 1和3的瓦片n+2,也可以变成集合)并继续。

如果您到达空手,则该手有效。

例如,对于您的无效手牌,总数为 60,这意味着 M = {3,6,9}:

Remove the 3: 112244556789
 - Start with 1: there are less than three, so remove a street
   -> impossible: 123 needs a 3

Remove the 6: impossible, there is only one

Remove the 9: impossible, there is only one

对于第二个示例12345555678999,总数为 78,这意味着 M = {3,6,9}:

Remove the 3: impossible, there is only one

Remove the 6: impossible, there is only one

Remove the 9: 123455556789
 - Start with 1: there is only one, so remove a street
   -> 455556789
 - Start with 4: there is only one, so remove a street
   -> 555789
 - Start with 5: there are three, so remove a set
   -> 789
 - Start with 7: there is only one, so remove a street
   -> empty : hand is valid, removals were [99] [123] [456] [555] [789]

你的第三个例子11223378888999也有78个,导致回溯:

Remove the 3: 11227888899
 - Start with 1: there are less than three, so remove a street
   -> impossible: 123 needs a 3

Remove the 6: impossible, there are none

Remove the 9: 112233788889
 - Start with 1: there are less than three, so remove streets
   -> 788889
 - Start with 7: there is only one, so remove a street
   -> 888
 - Start with 8: there are three, so remove a set
   -> empty, hand is valid, removals were : [99] [123] [123] [789] [888]

【讨论】:

  • 优秀的答案。我还在想是否有什么情况会导致错误拒绝……但我还没有找到一个例子。
  • 没有。提供了算法的正确性证明;-)
  • 很好的例子解释。这对我帮助很大!
  • 请注意,如果我们知道一手牌只由序列组成,那么它总是可以通过强制从最小数字开始的序列来确定。例如 122333445567 -> 123 234 345 567。因此更实用的是 1)根据上述方法找到一对 2)通过反复试验检查三元组。对于 14 张麻将牌,最多有 4 个可能的三元组,因此 2^4=16 次试验。 3)检查其余的手是否可以拆分为所有序列。每 14 个牌手最多 40 次试验,比回溯更容易实现。
【解决方案2】:

有一种特殊情况,您需要进行一些返工才能使其正确。这种情况发生在三人组和一对具有相同价值(但花色不同)的情况下。

b 赠竹,c 赠字,d 赠点,试试这个手:

b2,b3,b4,b5,b6,b7,c4,c4,c4,d4,d4,d6,d7,d8

d4,d4 should serve as the pair, and c4,c4,c4 should serve as the run-of-3 set.

但是由于 3 个“c4”牌出现在 2 个 d4 牌之前,所以前 2 个 c4 牌将作为对被拾取,留下一个孤立的 c4 和 2 个 d4,这 3 个牌不会形成有效的集合.

在这种情况下,您需要将 2 个 c4 牌“归还”给手牌(并保持手牌排序),并搜索下一个符合条件的牌(值 == 4)。为此,您需要让代码“记住”它曾尝试过 c4,因此在下一次迭代中它应该跳过 c4 并查找值 == 4 的其他图块。代码会有点混乱,但可行。

【讨论】:

  • 仔细观察并意识到我们不需要“记住”失败的瓷砖。在尝试了一对候选但未能清理手之后,我们可以继续循环并在列表中进一步搜索。半伪代码:
  • int[][] pair_idx = {{3,6,9},{2,5,8},{1,4,7}}; for (int j = 0; j
  • 在行尾尝试了“2 个空格”,但换行无法正常工作?
【解决方案3】:

我会把它分成两个步骤。

  1. 找出可能的组合。我认为对这些数字进行详尽的检查是可行的。此步骤的结果是一个组合列表,其中每个组合都有一个类型(集合、街道或对)和一个带有所用卡片的图案(可能是位图)。
  2. 利用前面的信息,确定可能的组合集合。这是位图派上用场的地方。使用按位运算符,您可以看到不同组合子在使用相同图块时会出现重叠。

您还可以执行第 1.5 步,检查每种类型是否足够可用。这一步和第 2 步将是您能够创建通用算法的地方。对于所有数量的图块和可能的组合,第一步将是相同的。

【讨论】:

    猜你喜欢
    • 2023-03-11
    • 1970-01-01
    • 2018-09-03
    • 2016-07-20
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多