WOO logo

将七张牌的位置转换为一个数字

这篇通讯发布时,距离日全食还有四天。我希望你们都兴奋不已,也希望所有体力和经济条件允许、能够在全食带上观赏日全食的人都能兴奋不已。可惜的是,我计划去德克萨斯州观看日全食,天气预报显示当天会有雷暴。不过,我仍然希望天空晴朗。

在进入正题之前,我上一篇关于复活节琐事的简报收到了一些出人意料的强烈反响。看来你们当中有些人对圣经相当了解,并对我的一些回答提出了质疑。以下是两个主要抗议问题,它们之间密切相关:

问题8:犹大后来把钱还给了那些被雇来背叛耶稣的祭司。他们怎么处理这些钱呢?

答案8:他们买了一块窑户的田,那里埋葬着无人认领的尸体。(马太福音27:6-8)

有人向我指出,《使徒行传》对那30块银币的去向有不同的描述。其中说犹大自己买了窑户的一块田(使徒行传1:18)。

问题 9:犹大是如何自杀的?

答案9:绞刑(马太福音27:3-5)

再说一次,《使徒行传》似乎另有版本。我不太明白该如何理解,就让经文自己解释吧:“犹大用他作恶所得的工价买了一块田,就在那里仆倒,身体崩裂,肠子流出来。”——使徒行传 1:18。

我的理解是,犹大病了,浑身肿胀,溃疡暴露。最后,他虚弱无力,摔倒在地,肠子都裂开了。这次摔倒可能是故意的。

在研究这个问题的过程中,我发现一些圣经无误论的拥护者竭尽全力试图将这两个故事混为一谈,形成一个错综复杂的故事。然而,我对这样的解释只能翻白眼。

好了,让我们进入本周的主题:高效编码,如何让七张牌的扑克牌手得分。考虑到计算机的速度,这似乎不是什么大问题。然而,终极德州扑克需要分析56万亿种发牌方式。每种方式都需要两手七张牌的牌型才能算出结果。如果不走捷径,这可能需要数年时间。

从一副 52 张牌的牌组中选出七张牌,一共有 combin(52,7) = 133,784,560 种方法。一个重要的省时技巧是给每种可能的组合都打分一次,并将分数保存到一个数组中。但是,如何将七张牌分别放到数组中的一个位置呢?

在给出我的答案之前,有人可能会建议使用一个大小为 52^7 的七维数组。这样的数组需要保存 1,028,071,702,528 个整数。我认为任何台式电脑都无法允许分配这么大的内存。不,我们需要以某种方式将 7 张卡片映射到 0 到 133,784,559 之间的整数。我的 C++ 编译器可以毫无问题地处理这种大小的数组。

首先,将每张牌赋值给一个从 0 到 51 的整数。你可以按照自己喜欢的方式进行。我个人会先将 2 赋值给 0 到 3,3 赋值给 4 到 7,以此类推,直到 A,赋值范围从 48 到 51。重要的是,当你用 4 除以一张牌时,余数必须始终是同一花色。例如,所有红桃的模数可能都是 0,空格是 1,梅花是 2,方块是 3。

我的函数将把最低的一组卡片 0,1,2,3,4,5,6 映射到数字 0。同样,最大的一组 45,46,47,48,49,50,51 将映射到最大值 133,784,559。

举例来说,让我们考虑一组编号为 5、10、15、20、25、30、35 的卡片,并确定该组卡片应映射到哪个整数。

首先,考虑最小的牌,数字 5。我们可以跳过很多包含至少一张数字 0 到 4 的牌的组合。从剩下的 47 张牌中选出 7 张的方法数为 combin(47,7) = 62,891,499。如前所述,从 52 张牌中选出 7 张的方法数为 combin(52,7) = 133,784,560。因此,我们可以跳过 133,784,560 - 62,891,499 = 70,893,061 个至少包含一张数字 0 到 4 的牌的组合。

接下来,考虑第二张牌的点数为 10。我们可以跳过更多包含至少一张点数在 6 到 9 之间的牌的组合。从牌堆剩余的 42 张牌中选出剩下的 6 张牌的方法数为 combin(42,6) = 5,245,786。这相当于从 combin(46,6)=9,366,819 种可能的方法中选择第一张牌点数大于 5 的另外六张牌。因此,对于包含至少一张点数在 6 到 9 之间的牌组,我们可以跳过 9,366,819-5,245,786=4,121,033 个数字。

接下来,考虑第三张牌,其值为 15。我们可以跳过更多涉及至少一张 11 到 14 范围内的牌的组合。从牌堆剩下的 37 张牌中选择剩下的 5 张牌的方法数为 combin(37,5) = 435,897。这就排除了 combin(41,5)=749,398 种可能的组合,用于选择第二张牌点数大于 10 的另外五张牌。因此,对于至少包含一张 11 到 14 之间的点数的牌组,我们可以跳过 749,398-435,897=313,501 个数字。

接下来,考虑第四张牌,其点数为 20。我们可以跳过更多包含至少一张点数在 16 到 19 之间的牌的组合。从牌堆剩余的 32 张牌中,选择剩余 4 张牌的方法数为 combin(32,4) = 35,960。而选择第三张牌点数大于 15 的另外四张牌的方法数为 combin(36,4) = 58,905。因此,对于包含至少一张点数在 16 到 19 之间的牌组,我们可以跳过 58,905-35,960=22,945 个数字。

接下来,考虑第五张牌,其点数为 25。我们可以跳过更多包含至少一张点数在 21 到 24 之间的牌的组合。从牌堆剩下的 27 张牌中选出剩下的三张牌的方法数为 combin(27,3) = 2,925。而从 combin(31,3) = 4,495 种可能的方法中,选出第四张牌点数大于 20 的另外三张牌。因此,对于包含至少一张点数在 21 到 24 之间的牌组,我们可以跳过 4,495-2,925=1,570 个数字。

接下来,考虑第六张牌,其点数为 30。我们可以跳过更多包含至少一张点数在 26 到 29 之间的牌的组合。从牌堆剩下的 22 张牌中选出剩下的两张牌的方法数为 combin(22,2) = 231。从 combin(26,3) = 325 种可能的方法中选出第五张牌点数大于 20 的另外两张牌。因此,对于包含至少一张点数在 26 到 29 之间的牌组,我们可以跳过 325-231=94 个数字。

现在只剩下一张牌了。从第六张牌来看,它的数字一定大于30。事实上,我们知道它是35。所以,我们可以跳过31到34这四张牌,直接选择第七张牌。

总共,我们跳过了 70,893,061+4,121,033+313,501+22,945+1,570+94+4 = 75,352,208 张卡片。

由于我们从零开始编号,就像所有优秀的程序员一样,我们可以将值分配给数字集 5,10,15,20,25,30,35 到数字 75,352,208。

当然,同样的逻辑适用于任何大小的牌组以及从中选择任意数量的牌。

下周我计划至少向您提供一份关于 2024 年 4 月 8 日日全食的初步报告!