如何使用 VBA 生成 52 张卡片组的所有 4 张卡片组合?

How can I generate all 4 card combinations of a 52 card deck using VBA?

我正在尝试使用一副 52 张牌来生成 4 张牌的所有组合。生成所有排列很容易(而且很长),但在卡片中,顺序无关紧要,因此例如 Ah、Kh、Qh、Jh 将与 Kh、Ah、Qh、Jh 相同。任何人都可以指出我正确的方向或向我展示一些我可以使用的示例代码吗?发现之前没有人尝试过这个很奇怪。

使用 4 个嵌套循环。为了防止重复并且只计算 "unique sets",我认为你只需要让每个循环开始于:[the 'parent' loop's current value] + 1


代码如下:

Option Explicit

Sub All4Combos()

    'Caution!  Save your work before runnning! (or set constant smaller)

    Const NumCardsInDeck = 52
    Dim c1, c2, c3, c4
    Dim p As Long

    For c1 = 1 To NumCardsInDeck
        For c2 = c1 + 1 To NumCardsInDeck
            For c3 = c2 + 1 To NumCardsInDeck
               For c4 = c3 + 1 To NumCardsInDeck

                    p = p + 1
                    Debug.Print c1, c2, c3, c4

                Next c4
            Next c3
        Next c2
    Next c1

    Debug.Print p & " Combinations of " & NumCardsInDeck & " cards"

End Sub

结果:

排列数:

52 x 51 x 50 x 49

组合数:

Permuations / slots!
--OR--
(52 x 51 x 50 x 49) / (4 x 3 x 2 x 1)

结果是270725种组合。

这是包含 10 张卡片的结果集:

1,2,4,10
1,2,5,6
1,2,5,7
1,2,5,8
1,2,5,9
1,2,5,10
1,2,6,7
1,2,6,8
1,2,6,9
1,2,6,10
1,2,7,8
1,2,7,9
1,2,7,10
1,2,8,9
1,2,8,10
1,2,9,10
1,3,4,5
1,3,4,6
1,3,4,7
1,3,4,8
1,3,4,9
1,3,4,10
1,3,5,6
1,3,5,7
1,3,5,8
1,3,5,9
1,3,5,10
1,3,6,7
1,3,6,8
1,3,6,9
1,3,6,10
1,3,7,8
1,3,7,9
1,3,7,10
1,3,8,9
1,3,8,10
1,3,9,10
1,4,5,6
1,4,5,7
1,4,5,8
1,4,5,9
1,4,5,10
1,4,6,7
1,4,6,8
1,4,6,9
1,4,6,10
1,4,7,8
1,4,7,9
1,4,7,10
1,4,8,9
1,4,8,10
1,4,9,10
1,5,6,7
1,5,6,8
1,5,6,9
1,5,6,10
1,5,7,8
1,5,7,9
1,5,7,10
1,5,8,9
1,5,8,10
1,5,9,10
1,6,7,8
1,6,7,9
1,6,7,10
1,6,8,9
1,6,8,10
1,6,9,10
1,7,8,9
1,7,8,10
1,7,9,10
1,8,9,10
2,3,4,5
2,3,4,6
2,3,4,7
2,3,4,8
2,3,4,9
2,3,4,10
2,3,5,6
2,3,5,7
2,3,5,8
2,3,5,9
2,3,5,10
2,3,6,7
2,3,6,8
2,3,6,9
2,3,6,10
2,3,7,8
2,3,7,9
2,3,7,10
2,3,8,9
2,3,8,10
2,3,9,10
2,4,5,6
2,4,5,7
2,4,5,8
2,4,5,9
2,4,5,10
2,4,6,7
2,4,6,8
2,4,6,9
2,4,6,10
2,4,7,8
2,4,7,9
2,4,7,10
2,4,8,9
2,4,8,10
2,4,9,10
2,5,6,7
2,5,6,8
2,5,6,9
2,5,6,10
2,5,7,8
2,5,7,9
2,5,7,10
2,5,8,9
2,5,8,10
2,5,9,10
2,6,7,8
2,6,7,9
2,6,7,10
2,6,8,9
2,6,8,10
2,6,9,10
2,7,8,9
2,7,8,10
2,7,9,10
2,8,9,10
3,4,5,6
3,4,5,7
3,4,5,8
3,4,5,9
3,4,5,10
3,4,6,7
3,4,6,8
3,4,6,9
3,4,6,10
3,4,7,8
3,4,7,9
3,4,7,10
3,4,8,9
3,4,8,10
3,4,9,10
3,5,6,7
3,5,6,8
3,5,6,9
3,5,6,10
3,5,7,8
3,5,7,9
3,5,7,10
3,5,8,9
3,5,8,10
3,5,9,10
3,6,7,8
3,6,7,9
3,6,7,10
3,6,8,9
3,6,8,10
3,6,9,10
3,7,8,9
3,7,8,10
3,7,9,10
3,8,9,10
4,5,6,7
4,5,6,8
4,5,6,9
4,5,6,10
4,5,7,8
4,5,7,9
4,5,7,10
4,5,8,9
4,5,8,10
4,5,9,10
4,6,7,8
4,6,7,9
4,6,7,10
4,6,8,9
4,6,8,10
4,6,9,10
4,7,8,9
4,7,8,10
4,7,9,10
4,8,9,10
5,6,7,8
5,6,7,9
5,6,7,10
5,6,8,9
5,6,8,10
5,6,9,10
5,7,8,9
5,7,8,10
5,7,9,10
5,8,9,10
6,7,8,9
6,7,8,10
6,7,9,10
6,8,9,10
7,8,9,10
210 Combinations of 10 cards

这基本上是 "how many handshakes" 问题的扩展版本....

有几种方法可以解决 - 一种是 brute-force 它(生成 all 排列,将所有元素排序为 card/suit 顺序,然后删除重复项)

第二个选择是创建一副牌并按顺序完成 ("card 1 can be paired up with cards 2-52, pair 1&2 can be triaded up with cards 3-52, triad 1&2&3 can be quarteted up with cards 4-52") 并从堆栈中移除 'used' 张卡片以进行下一个循环 ("triad 1&2&4 can be quarteted up with cards 5-52, pair 1&3 can be triaded up with cards 4-52, card 2 can be paired up with cards 3-52") 这将然后停在四重奏 49&50&51&52

而且,是的,您的工作簿需要很长时间才能解决这些问题。虽然没有完整的 6,497,400 个排列,但仍然有 270,725 个组合。

对上面提供的代码进行了一些更改。这是最终结果。

Option Explicit

Sub All4Combos()

Dim Cards() As String

'Caution!  Save your work before runnning! (or set constant smaller)

Cards = Split("As,Ks,Qs,Js,Ts,9s,8s,7s,6s,5s,4s,3s,2s,Ah,Kh,Qh,Jh,Th,9h,8h,7h,6h,5h,4h,3h,2h,Ad,Kd,Qd,Jd,Td,9d,8d,7d,6d,5d,4d,3d,2d,Ac,Kc,Qc,Jc,Tc,9c,8c,7c,6c,5c,4c,3c,2c", ",")
Const NumCardsInDeck = 51
Dim c1, c2, c3, c4
Dim p As Long
p = 0
For c1 = 0 To NumCardsInDeck
    For c2 = c1 + 1 To NumCardsInDeck
        For c3 = c2 + 1 To NumCardsInDeck
           For c4 = c3 + 1 To NumCardsInDeck

                p = p + 1
                Cells(p, 1) = Cards(c1) & Cards(c2) & Cards(c3) & Cards(c4)

            Next c4
        Next c3
    Next c2
Next c1


End Sub

为了好玩

基于 ashleedawg 的代码并将结果写入文本文件我得到了这个结果:

Run took 2293 milliseconds
Wrote cardcombos.txt with 270725 lines of 4-card combinations of totally 52 cards

将代码移植到 C++ 产生了这个:

Run took 203 milliseconds
Wrote cardcombos.txt with 270725 lines of 4-card combinations of totally 52 cards

如果我们将牌分成 4 套,每套 13 张牌,并以此为基础,那么 4 张牌有 5 种不同的组合,可以撤回,如果我们只考虑花色的唯一性:

  • ♥♦♣♠ - 四种不同的花色
  • ♥♦♣♣ - 三种不同的花色
  • ♣♣♥♥ - 两种不同的花色 (2:2)
  • ♣♣♣♥ - 两种不同花色 (3:1)
  • ♥♥♥♥ - 仅一套

现在,差不多,如果模拟所有花色的所有这些可能性,5 次模拟的总和应该等于 (49x50x51x52)/(4x3x2) = 270725


♥♦♣♠

For cnt1 = 1 To totalCards
    For cnt2 = 1 To totalCards
        For cnt3 = 1 To totalCards
            For cnt4 = 1 To totalCards
                numberResult = numberResult + 1
            Next : Next : Next : Next

四个嵌套循环正是所需要的。对于每个花色 totalCards=13numberResult*4,我们得到 28561。或者 13^4.


♥♦♣♣

For cnt1 = 1 To totalCards
    For cnt2 = cnt1 + 1 To totalCards
        For cntA = 1 To 3
            For cnt3 = 1 To totalCards
                For cnt4 = 1 To totalCards
                    numberResult = numberResult + 1
                Next : Next : Next : Next : Next

这里的思路是,每两张同花色的牌,有一个花色,我们的计算中没有。于是,cntA = 1 To 3。最后,我们将每个花色乘以 4 得到 158184.


♣♣♥♥

For cnt1 = 1 To totalCards
    For cnt2 = cnt1 + 1 To totalCards
        For cnt3 = 1 To totalCards
            For cnt4 = cnt3 + 1 To totalCards
                numberResult = numberResult + 1
            : Next : Next : Next : Next

对于 2 张同花色的牌,我们有 78 种可能性。这是用前两个嵌套循环模拟的。另一种颜色的其他 78 种可能性与接下来的 2 个嵌套循环有关。因此,我们有 6084 个变体。然而,将4花色组合成2花色的并集的方式是6种(♥♣,♥♦,♥♠,♣♦,♣♠,♦♠),因此我们将结果乘以6得到36504.


♣♣♣♥

For cnt1 = 1 To totalCards
    For cnt2 = cnt1 + 1 To totalCards
        For cnt3 = cnt2 + 1 To totalCards
            For cnt4 = 1 To totalCards
                numberResult = numberResult + 1
            Next : Next : Next : Next

这里我们有 3 张相同的牌和一张不同的牌。每 1 套 3 张相同的牌,我们可能有 3 张不同的牌。我们有 4 套花色,因此,我们必须乘以 12 (4x3) 得到 44616.


♥♥♥♥

For cnt1 = 1 To totalCards
    For cnt2 = cnt1 + 1 To totalCards
        For cnt3 = cnt2 + 1 To totalCards
            For cnt4 = cnt3 + 1 To totalCards
                numberResult = numberResult + 1
            Next : Next : Next : Next

这与公认的答案完全一样,但在这种情况下是我们的 totalCards = 13。就我们有 4 种不同的花色而言,我们乘以 4 得到 2860.


这是代码的结果:

 28561  4 different suits.
158184  3 different suits.
 36504  2(2:2) different suits.
 44616  2(3:1) different suits.
  2860  1 suit only.
270725  All.270725

最后,代码来了:

Public Sub TestMe()

    Dim cnt1&, cnt2&, cnt3&, cnt4&, cntA&
    Dim totalCards&: totalCards = 13
    Dim numberResult&, totalResult&

    '4 different suits
    For cnt1 = 1 To totalCards
        For cnt2 = 1 To totalCards
            For cnt3 = 1 To totalCards
                For cnt4 = 1 To totalCards
                    numberResult = numberResult + 1
                Next: Next: Next: Next
    numberResult = numberResult
    Debug.Print " " & numberResult & vbTab & "4 different suits."
    totalResult = numberResult + totalResult
    numberResult = 0

    '3 different suits
    For cnt1 = 1 To totalCards
        For cnt2 = cnt1 + 1 To totalCards
            For cntA = 1 To 3
                For cnt3 = 1 To totalCards
                    For cnt4 = 1 To totalCards
                        numberResult = numberResult + 1
                    Next: Next: Next: Next: Next
    numberResult = numberResult * 4
    Debug.Print numberResult & vbTab & "3 different suits."
    totalResult = numberResult + totalResult
    numberResult = 0

    '2 different suits (2+2)
    For cnt1 = 1 To totalCards
        For cnt2 = cnt1 + 1 To totalCards
            For cnt3 = 1 To totalCards
                For cnt4 = cnt3 + 1 To totalCards
                    numberResult = numberResult + 1
                Next: Next: Next: Next
    numberResult = numberResult * 6
    Debug.Print " " & numberResult & vbTab & "2(2:2) different suits."
    totalResult = numberResult + totalResult
    numberResult = 0

    '2 different suits (3+1)
    For cnt1 = 1 To totalCards
        For cnt2 = cnt1 + 1 To totalCards
            For cnt3 = cnt2 + 1 To totalCards
                For cnt4 = 1 To totalCards
                    numberResult = numberResult + 1
                Next: Next: Next: Next
    numberResult = numberResult * 12
    Debug.Print " " & numberResult & vbTab & "2(3:1) different suits."
    totalResult = numberResult + totalResult
    numberResult = 0

    '1 different suit
    For cnt1 = 1 To totalCards
        For cnt2 = cnt1 + 1 To totalCards
            For cnt3 = cnt2 + 1 To totalCards
                For cnt4 = cnt3 + 1 To totalCards
                    numberResult = numberResult + 1
                Next: Next: Next: Next
    numberResult = numberResult * 4
    Debug.Print "  " & numberResult & vbTab & "1 suit only."
    totalResult = numberResult + totalResult
    numberResult = 0

    Debug.Print totalResult & vbTab & "All." & (49& * 50 * 51 * 52) / (4 * 3 * 2)

End Sub