寻找街道和手中同类的算法
这实际上是一个基于麻将的问题,但是基于罗姆甚至扑克的背景也很容易理解。
在麻将中,14 张牌(牌类似于扑克中的牌)被排列成 4 组和一对。一条街道(“123”)始终只使用 3 个瓷砖,不多也不少。一组相同类型的(“111”)也恰好由 3 个瓷砖组成。这导致总和为 3 * 4 + 2 = 14 个图块。
还有各种例外,例如《坎》或《十三孤儿》,与此处无关。颜色和值范围 (1-9) 对于算法来说也不重要。
我正在尝试确定是否可以按照上述方式安排手牌。由于某些原因,它不仅应该能够处理 14 个图块,还应该能够处理任意数量的图块。 (下一步是找出需要交换多少张牌才能完成一手牌。)
示例:
11122233344455
- 很简单,4 组和一对。12345555678999
- 123、456、789、555、9911223378888999
- 123、123、789、888、9911223344556789
- 不是有效的手牌
我当前尚未实现的想法是这样的:对于每个图块,尝试制作a)一条街道b)一组c)一对。如果没有一个有效(或者有 > 1 对),则返回到上一次迭代并尝试下一个选项,或者,如果这是最高级别,则失败。否则,从剩余图块列表中删除已使用的图块并继续下一次迭代。
我相信这种方法有效,而且速度也相当快(性能是一个“不错的奖励”),但我对你对此的看法很感兴趣。你能想到替代解决方案吗?这个或类似的东西已经存在吗?
(不是作业,我正在学习打麻将。)
This is actually a Mahjong-based question, but a Romme- or even Poker-based background will also easily suffice to understand.
In Mahjong 14 tiles (tiles are like cards in Poker) are arranged to 4 sets and a pair. A street ("123") always uses exactly 3 tiles, not more and not less. A set of the same kind ("111") consists of exactly 3 tiles, too. This leads to a sum of 3 * 4 + 2 = 14 tiles.
There are various exceptions like Kan or Thirteen Orphans that are not relevant here. Colors and value ranges (1-9) are also not important for the algorithm.
I'm trying to determine if a hand can be arranged in the way described above. For certain reasons it should not only be able to deal with 14 but any number of tiles. (The next step would be to find how many tiles need to be exchanged to be able to complete a hand.)
Examples:
11122233344455
- easy enough, 4 sets and a pair.12345555678999
- 123, 456, 789, 555, 9911223378888999
- 123, 123, 789, 888, 9911223344556789
- not a valid hand
My current and not yet implemented idea is this: For each tile, try to make a) a street b) a set c) a pair. If none works (or there would be > 1 pair), go back to the previous iteration and try the next option, or, if this is the highest level, fail. Else, remove the used tiles from the list of remaining tiles and continue with the next iteration.
I believe this approach works and would also be reasonably fast (performance is a "nice bonus"), but I'm interested in your opinion on this. Can you think of alternate solutions? Does this or something similar already exist?
(Not homework, I'm learning to play Mahjong.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
街道和集合中的值之和可以除以 3:
因此,如果将解开一手牌后,您将得到 3N + 2M 形式的数字,其中 M 是该对牌中牌的值。对于 M 的每个值,除以三的余数 (
total % 3
) 为:因此,您不必测试九个可能的对,而只需根据简单的加法尝试三个。对于每个可能的对,删除具有该值的两个图块,然后继续算法的下一步以确定是否可能。
一旦有了这个,就从最低的值开始。如果具有该值的图块少于三个,则意味着它们必然是街道的第一个元素,因此请删除该街道(如果不能,因为图块 n+1 或 n+2 丢失,则意味着手牌无效)并转到下一个最低值。
如果至少有三个具有最低值的图块,请将它们作为一组移除(如果您问“如果它们是街道的一部分怎么办?”考虑一下,如果它们是,那么还有三个图块 n+1 和三个图块n+2 块,也可以变成集合)并继续。
如果你拿到的是空手牌,则该手牌有效。
例如,对于您的无效手牌,总数为 60,这意味着 M = {3,6,9}:
对于您的第二个示例
12345555678999
,总数为 78,这意味着 M = {3,6 ,9}:你的第三个例子 11223378888999 总共也有 78,这会导致回溯:
The sum of the values in a street and in a set can be divided by 3:
So, if you add together all the numbers in a solved hand, you would get a number of the form 3N + 2M where M is the value of the tile in the pair. The remainder of the division by three (
total % 3
) is, for each value of M :So, instead of having to test nine possible pairs, you only have to try three based on a simple addition. For each possible pair, remove two tiles with that value and move on to the next step of the algorithm to determine if it's possible.
Once you have this, start with the lowest value. If there are less than three tiles with that value, it means they're necessarily the first element of a street, so remove that street (if you can't because tiles n+1 or n+2 are missing, it means the hand is not valid) and move on to the next lowest value.
If there are at least three tiles with the lowest value, remove them as a set (if you ask "what if they were part of a street?" consider that if they were, then there are also three of tile n+1 and three of tile n+2, which can also be turned into sets) and continue.
If you reach an empty hand, the hand is valid.
For example, for your invalid hand the total is 60, which means M = {3,6,9}:
With your second example
12345555678999
, the total is 78, which means M = {3,6,9}:Your third example 11223378888999 also has a total of 78, which causes backtracking:
有一种特殊情况,您需要进行一些返工才能使其正确。当存在三连胜和一对具有相同值(但花色不同)时,就会发生这种情况。
设b代表竹子,c代表字符,d代表点,试试这手牌:
但是因为3个“c4”牌出现在2个d4牌之前,所以前2个c4牌将被作为对拾取,留下一个孤儿c4和 2 个 d4,这 3 个图块不会形成有效的集合。
在这种情况下,您需要将 2 个 c4 牌“返回”到手上(并保持手牌排序),并搜索下一个满足条件的牌(值 == 4)。为此,您需要使代码“记住”它已尝试过 c4,因此在下一次迭代中它应该跳过 c4 并查找值 == 4 的其他图块。代码会有点混乱,但可行。
There is a special case that you need to do some re-work to get it right. This happens when there is a run-of-three and a pair with the same value (but in different suit).
Let b denates bamboo, c donates character, and d donates dot, try this hand:
But because the 3 "c4" tiles appear before the 2 d4 tiless, the first 2 c4 tiles will be picked up as the pair, leaving an orphan c4 and 2 d4s, and these 3 tiles won't form a valid set.
In this case, you'll need to "return" the 2 c4 tiles back to the hand (and keep the hand sorted), and search for next tile that meets the criteria (value == 4). To do that you'll need to make the code "remember" that it had tried c4 so in next iteration it should skip c4 and looks for other tiles with value == 4. The code will be a bit messy, but doable.
我会把它分成两步。
您还可以执行步骤 1.5,仅检查每种类型是否有足够的可用。在这一步和步骤 2 中,您将能够创建通用算法。对于所有数量的图块和可能的组合,第一步都是相同的。
I would break it down into 2 steps.
You could also do a step 1.5 where you just check to see if enough of each type is available. This step and step 2 would be where you would be able to create a general algorithm. The first step would be the same for all numbers of tiles and possible combinations quickly.