一副纸牌的所有不重复组合

All non-repeating combinations of a deck of cards

我正在尝试编写一个扑克赔率计算器。它背后的想法是,它通过所有可能打出的纸牌组合来强制执行。

我目前的逻辑(为了便于阅读而精简)如下;

    For i = 0 To unknownCards - 1
            For j = 1 To 4
                'pick suit

                For k = 1 To 13
                    'pick number

                      'do other work here

                Next
            Next
        Next

然而这是错误的。它只会按顺序遍历卡片。出于我的目的,卡片的顺序并不重要(例如,我不想分别处理 2、3、4 和 4、3、2),但重要的是我看到每一种可能的独特组合。我只是不知道该怎么做?任何帮助或建议都会很棒。

P.S。我在 VB.net

中这样做

评论澄清后:要暴力获取所有手牌的列表,我知道的最简单的方法是对牌施加顺序(例如按数字排序,然后是花色:标准是梅花 2低,黑桃 A 高)然后选择升序排列的手牌。这样即使顺序对您来说无关紧要,但对您的手牌进行排序可确保您有一种明确的方式来决定独特的手牌。

一个,简单易懂但不是最佳的方法是嵌套 5 个循环:第一张牌的整个牌组,然后通过遍历低于该牌的所有牌来选择第二张牌,依此类推在。 (实际上,您可以从一副牌的第五张开始选择第一张牌,即梅花 3 张,依此类推,但完成后确保每手有 5 张牌可能更容易。)

我选择的语言是Python;如果你想要完整的列表,我会列出 52 张卡片,或者更好的是只给卡片编号和使用范围;然后在列表中使用 itertools.product 5 次以上,只允许 card_1this question 了解其用法。对于迭代器,我会查看他们的文档代码并将其修改为仅允许递增的手。也许更有经验的编码人员可以建议最佳迭代器。

有 2,598,960 种可能的手牌。此代码通过暴力生成所有可能的手牌。只生成 52 张牌 指数 的组合比担心循环中的花色和等级更快/更容易/更好。正是@ElizabethSQGoodman 所说的,其中有 5 个嵌套循环,在我的例子中,每个循环的起点都比前一个高。

出于性能原因,我选择了一个字节来保存每张牌,并选择了一个结构来保存手牌。然后,稍后,您可以根据规则计算出每张牌是什么牌:前 13 张是梅花,接下来的 13 张是方块,等等(参见 getHumanReadableHand())。在那里您还可以定义 A 的高位或低位(但不能同时定义两者,抱歉!)。等级 (A, 2, 3, ..., J, Q, K) 由索引模 13 确定。花色由 13 的整数除法确定。

Module Module1

    Sub Main()
        Dim hands As New List(Of Hand)()
        For c0 As SByte = 0 To 51
            For c1 As SByte = c0 + 1 To 51
                For c2 As SByte = c1 + 1 To 51
                    For c3 As SByte = c2 + 1 To 51
                        For c4 As SByte = c3 + 1 To 51
                            Dim hand = New Hand
                            hand.Card0 = c0
                            hand.Card1 = c1
                            hand.Card2 = c2
                            hand.Card3 = c3
                            hand.Card4 = c4
                            hands.Add(hand)
                        Next c4
                    Next c3
                Next c2
            Next c1
        Next c0
        Console.WriteLine("There are {0} possible hands.", hands.Count)
        Dim rnd As New Random()
        Dim r = rnd.Next(hands.Count - 1)
        Console.WriteLine("Random hand: {0}", getHumanReadableHand(hands(r)))
        Console.WriteLine("Value: {0}", getHandValue(hands(r)))
        Console.ReadLine()
    End Sub

    Function getHumanReadableHand(hand As Hand) As String
        Static suits = {"C", "D", "H", "S"}
        Static ranks = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}
        Return String.Join(", ", hand.Cards.Select(Function(card) ranks(rank(card)) & suits(suit(card))))
    End Function

    Private Function rank(card As SByte) As SByte
        Return card Mod 13
    End Function

    Private Function suit(card As SByte) As SByte
        Return CSByte(card \ 13)
    End Function

    Function getHandValue(hand As Hand) As String
        Dim cards = hand.Cards
        If cards.Select(Function(card) rank(card)).Max() - cards.Select(Function(card) rank(card)).Min() = 4 AndAlso
            cards.Select(Function(card) rank(card)).Distinct().Count = 5 AndAlso
            cards.Select(Function(card) suit(card)).Distinct().Count = 1 Then
            Return "Straight Flush"
        ElseIf cards.OrderBy(Function(card) rank(card)).Take(4).Select(Function(card) rank(card)).Distinct().Count = 1 OrElse
            cards.OrderBy(Function(card) rank(card)).Skip(1).Take(4).Select(Function(card) rank(card)).Distinct().Count = 1 Then
            Return "Four of a Kind"
        ElseIf cards.Select(Function(card) rank(card)).Distinct().Count = 2 Then
            Return "Full House"
        ElseIf cards.Select(Function(card) suit(card)).Distinct().Count = 1 Then
            Return "Flush"
        ElseIf cards.Select(Function(card) rank(card)).Max() - cards.Select(Function(card) rank(card)).Min() = 4 AndAlso
            cards.Select(Function(card) rank(card)).Distinct().Count = 5 Then
            Return "Straight"
        ElseIf cards.OrderBy(Function(card) rank(card)).Take(3).Select(Function(card) rank(card)).Distinct().Count = 1 OrElse
            cards.OrderBy(Function(card) rank(card)).Skip(1).Take(3).Select(Function(card) rank(card)).Distinct().Count = 1 OrElse
            cards.OrderBy(Function(card) rank(card)).Skip(2).Take(3).Select(Function(card) rank(card)).Distinct().Count = 1 Then
            Return "Three of a Kind"
        ElseIf cards.Select(Function(card) rank(card)).Distinct().Count = 3 Then
            Return "Two Pairs"
        ElseIf cards.Select(Function(card) rank(card)).Distinct().Count = 4 Then
            Return "One Pair"
        Else
            Return "Garbage"
        End If
    End Function

    Structure Hand

        Public Property Card0 As SByte
        Public Property Card1 As SByte
        Public Property Card2 As SByte
        Public Property Card3 As SByte
        Public Property Card4 As SByte

        Public ReadOnly Property Cards As IEnumerable(Of SByte)
            Get
                Return New List(Of SByte)({Card0, Card1, Card2, Card3, Card4})
            End Get
        End Property

    End Structure

End Module

示例输出:

There are 2598960 possible hands.
Random hand: 2C, 5C, 2D, 5S, KS
Value: Two Pairs

此代码大约需要 60 毫秒才能在我的机器上生成所有可能的手牌。