How to Iterate Through Every Possible Combination of N Playing Cards

How can I iterate through every possible combination of n playing cards

You need all combinations of n items from a set of N items (in your case, N == 52, but I'll keep the answer generic).

Each combination can be represented as an array of item indexes, size_t item[n], such that:

  • 0 <= item[i] < N
  • item[i] < item[i+1], so that each combination is a unique subset.

Start with item[i] = i. Then to iterate to the next combination:

  • If the final index can be incremented (i.e. item[n-1] < N-1), then do that.
  • Otherwise, work backwards until you find an index that can be incremented, and still leave room for all the following indexes (i.e. item[n-i] < N-i). Increment that, then reset all the following indexes to the smallest possible values.
  • If you can't find any index that you can increment (i.e. item[0] == N-n), then you're done.

In code, it might look something vaguely like this (untested):

void first_combination(size_t item[], size_t n)
{
for (size_t i = 0; i < n; ++i) {
item[i] = i;
}
}

bool next_combination(size_t item[], size_t n, size_t N)
{
for (size_t i = 1; i <= n; ++i) {
if (item[n-i] < N-i) {
++item[n-i];
for (size_t j = n-i+1; j < n; ++j) {
item[j] = item[j-1] + 1;
}
return true;
}
}
return false;
}

It might be nice to make it more generic, and to look more like std::next_permutation, but that's the general idea.

How to loop through all the combinations of e.g. 48 choose 5

(disclaimer: I've written a very fast poker hand evaluator)

I want to enumerate / loop through all the 48 choose 5 possible
combinations of boards and count the times Player A wins and the times
Player B wins and when they tie.

You do not want to evaluate C(48,5) (1 712 304) hands every time you have a matchup between two players preflop: most programs simply use a precomputed lookup table between all the possible matchups between two players preflop.

For example say you have "Ac Ad" vs "7c 6c", you simply go look in a lookup table that contains: 1 333 573, 371 831, 6900 (where 1 333 573 is the number of times "Ac Ad" wins, 371 831 is the number of times "7c 6c" wins and 6 900 is the number of ties (they sum to 1 712 304). To gain some room you can discard the 6 900, knowing that the number of ties shall always be C(48,5) - (wins 1 + wins 2).

(more on the lookup table at the end of this answer)

But to answer your question:

I'm not sure how I can systematically loop through every 5 card
combination.

If you do really want to loop trough every combination, you have to know that poker hand evaluators are typically the kind of program that need to be very, very fast. These programs can typically evaluate hundreds of millions of hands per second (you read correctly: hundreds of millions).

When you need such high-performance "number crunching" you can forget about "design patterns" and "OO". What you want is raw speed.

For example the following will pass through the innermost loop C(48,5) times and it is quite fast:

    for ( int i = 0; i < n; i++ ) {
for ( int j = i + 1; j < n; j++ ) {
for ( int k = j + 1; k < n; k++ ) {
for (int l = k + 1; l < n; l++) {
for (int m = l + 1; m < n; m++) {
...
}
}
}
}
}

Once again for two players preflop it's probably a very bad idea: you're gonna be much faster by using a lookup table.

But for three players preflop (where it's impractical to use a preflop tables, there are too many matchups), you may want to loop like that, over C(46,5) hands, using the five nested loops (of course you need to use i,j,k,l,m to get the correct 5 cards out of the 46 cards that are left). Then, once you've got the 5 cards, you use a fast hand evaluator that gives you the best out of 7 (the 5 of the board + the two of each player).

Regarding the lookup table:

Most people use an approximated 169 vs 169 lookup table ("Ac Kd", "As Kh", "Ad Ks", etc. all become "AK offsuit" and the C(52,2) possible starting hands become grouped in 169 type of starting hands). The Wikipedia article explains how to get the 169 non-equivalent starting hands:

http://en.wikipedia.org/wiki/Texas_hold_%27em_starting_hands

They're non equivalent when you take one hand into account, but as soon as you do hand 1 vs hand 2 the "169 vs 169" is an approximation (a quite good one that said).

Of course you can get fancier. There are only C(52,2) (which gives 1326) real different Hold'em starting hands, which means it's very practical to build a perfect lookup table (no approximation at all) on modern computers (C(1326,2) ain't that big) if you really need perfect numbers. If you can live with approximation, go for the 169 vs 169 table (it would need C(169,2) or 14 196 entries).

PHP - Poker algorithm that creates all possible poker combinations

You have your starting deck already. The idea is to generate all permutations:

E.g.

   CARD NUMBER
1 2 3 4 5 6 7 8 9 10 11 12 13 ... 52
1 o x x x x x x x x x x x x x
2 - o x x x x x x x x x x x x
3 - - o x x x x x x x x x x x
4 - - - o x x x x x x x x x x
5 - - - - o x x x x x x x x x
6
7 ......... and so on .........
8
9
10
11
12
13
...
52

We have 52 cards in the deck (that's what you generated in $startingDeck):

The x denote the combination that we want to generate. Note that we don't have to generate the lower part of the matrix as the order does not matter in poker as you receive both cards at the same time. We also don't generate the axis as you can't have the same card twice (unless you cheat :)).

The idea now is to use two loops, but let the second loop start depending on the first initial $j depends on $i. That way we do not generate e.g. 2-1, 3-2, 3-1, ... again as we already generated 1-2, 1-3, 2-3, ....

So let's start:

for ($i = 0; i < count($startingDeck); $i++) {
// Ignore e.g. 2-1, 3-2, as we already generated 1-2, 2-3, and so on...
for ($j = $i+1; $j < count($startingDeck); $j++) {
$firstCard = $startingDeck[$i];
$secondCard = $startingDeck[$j];
// print my stuff
}
}

This generates the top matrix. The $i+1 makes sure that we don't generate the diagonal.

I hope that helps.

All possible combinations of card/poker hands for a set of players

I'd suggest using a recursive algorithm.

I'm using generators for the code to run in constant-space, as well as start producing results ASAP as opposed to a huge result at the end; see http://www.dabeaz.com/generators/ if you haven't heard of generators before.

As a side note, I'd suggest using a normalized data structure to hold your list of players and hand sizes to start with, so that the line with groupby wouldn't be necessary at all... And in any case, it's generally a good idea to keep your data normalized by default/most of the time and only use denormalized/flattened forms for example for certain algorithms that might need or run faster with flat structures.

Here's the code; feel free to propose clean-ups/simplifications:

from itertools import combinations, groupby, islice

cards = ["a", "b", "c", "d"]
players = ["1", "1", "2", "2"]

def hand_combinations(players, cards):
# convert ["1", "1", "2", "2"] into [("1", 2), ("2", 2)]
players = list((x, len(list(y))) for x, y in groupby(players))

# sets are faster to operate on in our case
cards = set(cards)

def generate(players, cards):
if not players:
yield []
else:
# pick the first player
player_name, player_hand_size = players[0]
# and then walk over all the possible hands for this player
for player_hand in combinations(cards, player_hand_size):
# for each hand, use the cards that are left to build all the
# possible hands for the rest of the players in this iteration
for tail in generate(players[1:], cards - set(player_hand)):
yield [(player_name, player_hand)] + tail

return generate(players, cards)

# take only the 100 first combinations; otherwise it'll take
# forever with the larger example
combos = islice(hand_combinations(players, cards), 0, 100)

# convert back to the flat structure
flattened = [
' '.join(
player_name + ':' + card
for player_name, player_cards in combo
for card in player_cards
)
for combo in combos
]

from pprint import pprint
pprint(flattened)

Outputs:

['1:a 1:c 2:b 2:d',
'1:a 1:b 2:c 2:d',
'1:a 1:d 2:c 2:b',
'1:c 1:b 2:a 2:d',
'1:c 1:d 2:a 2:b',
'1:b 1:d 2:a 2:c']

or with the larger examople:

['_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:9S _To:10D _Tc:8S',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:9S _To:8S _Tc:10D',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:10D _To:8S _Tc:9S',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:9S _To:10D _To:8S _Tc:AH',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:9S _To:8D _Tc:8S',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:9S _To:8S _Tc:8D',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:8D _To:8S _Tc:9S',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:9S _To:8D _To:8S _Tc:AH',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:9S _To:10D _Tc:8D',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:9S _To:8D _Tc:10D',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:10D _To:8D _Tc:9S',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:9S _To:10D _To:8D _Tc:8S',
...

All non-repeating combinations of a deck of cards

There are 2,598,960 possible hands. This code generates all possible hands through brute force. It's faster / easier / better to just generate the combinations of 52 card indices than to worry about suits and ranks in your loop. Exactly what @ElizabethSQGoodman said, where there are 5 nested loops, each starting higher than the previous in my case.

I opted for a byte to hold each card, and a struct to hold the hand, for performance reasons. Then, later, you can figure out what card each is based on rules: the first 13 cards are clubs, the next 13 are diamonds, etc. (see getHumanReadableHand()). There you can also define Ace high or low (but not both, sorry!). The rank (A, 2, 3, ..., J, Q, K) is determined by the index modulo 13. The suit is determined by integer division of 13 into the index.

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

Sample output:

There are 2598960 possible hands.

Random hand: 2C, 5C, 2D, 5S, KS

Value: Two Pairs

This code takes around 60 ms to generate all the possible hands on my machine.

Iterating through combinations of groups of 4 within a group of 16

Conceptually, this problem isn't that hard. All we need to do is generate all 16! permutations, and remove 4! of within-group repeats for all 4 groups. Finally, we need to remove 4! of repeats for the groups as a whole. So we should obtain nearly 3 million results:

16! / (4!^5) = 2,627,625

As an example, if we consider the first 10 permutations of 1 through 16 in lexicographical order, we have:

 1 (1 2 3 4) (5 6 7 8) (9 10 11 12) (13 14 15 16)
2 (1 2 3 4) (5 6 7 8) (9 10 11 12) (13 14 16 15)
3 (1 2 3 4) (5 6 7 8) (9 10 11 12) (13 15 14 16)
4 (1 2 3 4) (5 6 7 8) (9 10 11 12) (13 15 16 14)
5 (1 2 3 4) (5 6 7 8) (9 10 11 12) (13 16 14 15)
6 (1 2 3 4) (5 6 7 8) (9 10 11 12) (13 16 15 14)
7 (1 2 3 4) (5 6 7 8) (9 10 11 12) (14 13 15 16)
8 (1 2 3 4) (5 6 7 8) (9 10 11 12) (14 13 16 15)
9 (1 2 3 4) (5 6 7 8) (9 10 11 12) (14 15 13 16)
10 (1 2 3 4) (5 6 7 8) (9 10 11 12) (14 15 16 13)

As you can see, all of these are identical as the last group is the only thing that is being permuted (which the OP doesn't want). If we continue generating and look at permutations 20 through 30 we have:

20 (1 2 3 4) (5 6 7 8) (9 10 11 12) (16 13 15 14)
21 (1 2 3 4) (5 6 7 8) (9 10 11 12) (16 14 13 15)
22 (1 2 3 4) (5 6 7 8) (9 10 11 12) (16 14 15 13)
23 (1 2 3 4) (5 6 7 8) (9 10 11 12) (16 15 13 14)
24 (1 2 3 4) (5 6 7 8) (9 10 11 12) (16 15 14 13)
25 (1 2 3 4) (5 6 7 8) (9 10 11 13) (12 14 15 16) <- a different combination
26 (1 2 3 4) (5 6 7 8) (9 10 11 13) (12 14 16 15)
27 (1 2 3 4) (5 6 7 8) (9 10 11 13) (12 15 14 16)
28 (1 2 3 4) (5 6 7 8) (9 10 11 13) (12 15 16 14)
29 (1 2 3 4) (5 6 7 8) (9 10 11 13) (12 16 14 15)
30 (1 2 3 4) (5 6 7 8) (9 10 11 13) (12 16 15 14)

Finally at permutation #25, we get a new custom combination that the OP is after.

If we keep going, eventually permutation #5606234726401 (yes, that is over 5 trillion) is an example of where the groups are exactly the same as the first few permutations, only these groups are permuted (again, these are the arrangements we want to avoid):

5606234726401 (5 6 7 8) (1 2 3 4) (9 10 11 12) (13 14 15 16) <- same as the 1st permutation
5606234726402 (5 6 7 8) (1 2 3 4) (9 10 11 12) (13 14 16 15)
5606234726403 (5 6 7 8) (1 2 3 4) (9 10 11 12) (13 15 14 16)
5606234726404 (5 6 7 8) (1 2 3 4) (9 10 11 12) (13 15 16 14)
5606234726405 (5 6 7 8) (1 2 3 4) (9 10 11 12) (13 16 14 15)
5606234726406 (5 6 7 8) (1 2 3 4) (9 10 11 12) (13 16 15 14)
5606234726407 (5 6 7 8) (1 2 3 4) (9 10 11 12) (14 13 15 16)
5606234726408 (5 6 7 8) (1 2 3 4) (9 10 11 12) (14 13 16 15)
5606234726409 (5 6 7 8) (1 2 3 4) (9 10 11 12) (14 15 13 16)
5606234726410 (5 6 7 8) (1 2 3 4) (9 10 11 12) (14 15 16 13)

The point is, we need a method that will avoid these within-group as well as group permutations because the sheer computational power required (no matter how efficient are algorithm is) to generate and sift through that many permutations is simply not feasible.

We need a different approach. Let's look at a set of the combinations of 16 choose 4, say 450 through 460:

450 (1 12 14 16)
451 (1 12 15 16)
452 (1 13 14 15)
453 (1 13 14 16)
454 (1 13 15 16)
455 (1 14 15 16)
456 (2 3 4 5)
457 (2 3 4 6)
458 (2 3 4 7)
459 (2 3 4 8)
460 (2 3 4 9)

We note here, that if we were to fill in the other 3 groups with the combinations not present in the first 455 combinations, we would eventually replicate combinations 456 through 459. For example, the combinations 291 through 294 are:

291 (1 6 7 8) 
292 (1 6 7 9)
293 (1 6 7 10)
294 (1 6 7 11)

And if we were to fill in all of the possible combinations of the complement of each of these combinations choose 4 (e.g. (2 3 4 5 9 10 11 12 13 14 15 16) for the complement of 291), those combinations shown earlier (456 through 459) will already be accounted for.

This is a nice result. This means we can simply stop generating results after the first "group" has completed (e.g. while the 1st number in the 1st group stays 1). The same thinking applies as we move to further groups.

Below we have some helper functions for counting combinations, generating combinations, and getting the complement of a vector. The combination generator is very efficient and can generate all 5,200,300 combinations of 25 choose 12 in just over 3 seconds on my old Windows machine.

Option Explicit

Function nCr(n As Long, r As Long) As Long
Dim res As Long, i As Long, temp As Double
temp = 1
For i = 1 To r: temp = temp * (n - r + i) / i: Next i
nCr = Round(temp)
End Function

Sub GetCombosNoRep(ByRef combos() As Long, n As Long, r As Long, numRows As Long)

Dim index() As Long
Dim numIter As Long, i As Long, k As Long, count As Long

ReDim index(1 To r)
count = 1
For i = 1 To r: index(i) = i: Next

While count <= numRows
numIter = n - index(r) + 1

For i = 1 To numIter
For k = 1 To r
combos(count, k) = index(k)
Next k
count = count + 1
index(r) = index(r) + 1
Next i

For i = r - 1 To 1 Step -1
If index(i) <> (n - r + i) Then
index(i) = index(i) + 1
For k = i + 1 To r
index(k) = index(k - 1) + 1
Next k

Exit For
End If
Next i
Wend

End Sub

Sub GetComplement(n As Long, childVec() As Long, complementVec() As Long)

Dim i As Long, j As Long

ReDim logicalVec(1 To n)
For i = 1 To n: logicalVec(i) = True: Next i
For i = 1 To UBound(childVec): logicalVec(childVec(i)) = False: Next i
j = 1

For i = 1 To n
If logicalVec(i) Then
complementVec(j) = i
j = j + 1
End If
Next i

End Sub

And here is the main sub routine:

Sub MasterGenerator()

Dim myRows As Long, i As Long, j As Long, r As Long, n As Long
Dim combos() As Long, k As Long, gSize As Long, total As Long
Dim sTime As Double, eTime As Double, verbose As Boolean

n = CLng(InputBox("How many datasets do you have?", "ENTER # OF DATASETS", "16"))
r = CLng(InputBox("How many groups do you have?", "ENTER # OF GROUPS", "4"))
verbose = CBool(InputBox("Should the results be printed?", "VERBOSE OPTION", "True"))

If Abs(Round(n / r) - (n / r)) > 0.00001 Or r < 2 Or r >= n Then
MsgBox "Incorrect input!!!"
'' You could have custom message like: MsgBox "# of Datasets is NOT divisible by # of Groups!!!"
Exit Sub
End If

sTime = Timer
gSize = n / r
total = 1

Dim AllCombs() As Variant, tN As Long
ReDim AllCombs(1 To r - 1)
tN = n

For i = 1 To r - 1
myRows = nCr(tN, gSize)
ReDim combos(1 To myRows, 1 To gSize)
Call GetCombosNoRep(combos, tN, gSize, myRows)
total = total * myRows / (r - (i - 1))
AllCombs(i) = combos
tN = tN - gSize
Next i

Dim MasterGroups() As Long
ReDim MasterGroups(1 To total, 1 To r, 1 To gSize)

Dim secLength As Long, s As Long, e As Long, m As Long
secLength = nCr(n, gSize) / r

Dim v() As Long, child() As Long, q As Long, temp As Long
ReDim v(1 To n)
For i = 1 To n: v(i) = i: Next i

ReDim child(1 To gSize)
Dim superSecLen As Long, numReps As Long
superSecLen = total
Dim endChild() As Long, endV() As Long
ReDim endChild(1 To n - gSize)
ReDim endV(1 To gSize)

'' Populate all but the last 2 columns
If r > 2 Then
For i = 1 To r - 2
numReps = nCr(n - (i - 1) * gSize, gSize) / (r - (i - 1))
secLength = superSecLen / numReps
s = 1: e = secLength

If i = 1 Then
For j = 1 To numReps
For k = s To e
For m = 1 To gSize
MasterGroups(k, i, m) = v(AllCombs(i)(j, m))
Next m
Next k
s = e + 1
e = e + secLength
Next j
Else
ReDim child(1 To (i - 1) * gSize)
ReDim v(1 To n - (i - 1) * gSize)

While e < total
'' populate child vector so we can get the complement
For j = 1 To i - 1
For m = 1 To gSize
child(m + (j - 1) * gSize) = MasterGroups(s, j, m)
Next m
Next j

Call GetComplement(n, child, v)

For q = 1 To numReps
For k = s To e
For m = 1 To gSize
MasterGroups(k, i, m) = v(AllCombs(i)(q, m))
Next m
Next k
s = e + 1
e = e + secLength
Next q
Wend
End If

superSecLen = secLength
Next i

numReps = nCr(n - (r - 2) * gSize, gSize) / (r - 2)
s = 1: e = secLength

ReDim child(1 To (r - 2) * gSize)
ReDim v(1 To n - (r - 2) * gSize)

While e <= total
'' populate child vector so we can get the complement
For j = 1 To r - 2
For m = 1 To gSize
child(m + (j - 1) * gSize) = MasterGroups(s, j, m)
endChild(m + (j - 1) * gSize) = MasterGroups(s, j, m)
Next m
Next j

Call GetComplement(n, child, v)
q = 1

For k = s To e
For m = 1 To gSize
MasterGroups(k, r - 1, m) = v(AllCombs(r - 1)(q, m))
endChild(m + (r - 2) * gSize) = MasterGroups(k, r - 1, m)
Next m

q = q + 1
Call GetComplement(n, endChild, endV)

For m = 1 To gSize
MasterGroups(k, r, m) = endV(m)
Next m
Next k
s = e + 1
e = e + secLength
Wend
Else
For k = 1 To total
For m = 1 To gSize
MasterGroups(k, 1, m) = v(AllCombs(1)(k, m))
endChild(m) = MasterGroups(k, 1, m)
Next m

Call GetComplement(n, endChild, endV)

For m = 1 To gSize
MasterGroups(k, 2, m) = endV(m)
Next m
Next k
End If

If verbose Then
Dim myString As String, totalString As String, printTotal As Long
printTotal = Application.WorksheetFunction.Min(100000, total)

For i = 1 To printTotal
totalString = vbNullString
For j = 1 To r
myString = vbNullString
For k = 1 To gSize
myString = myString & " " & MasterGroups(i, j, k)
Next k
myString = Right(myString, Len(myString) - 1)
myString = "(" & myString & ") "
totalString = totalString + myString
Next j
Cells(i, 1) = totalString
Next i
eTime = Timer - sTime
MsgBox "Generation of " & total & " as well as printing " & printTotal & " custom combinations completed in : " & eTime & " seconds"
Else
eTime = Timer - sTime
MsgBox "Generation of " & total & " custom combinations completed in : " & eTime & " seconds"
End If

End Sub

I know it is a bit much, but it is very general and decently fast. If you run Sub MasterGenerator and enter 8 for the # of datasets, and 2 for the number of groups like this:

Sample Image
Sample Image
Sample Image

You get the following results:

Sample Image
Sample Image

For the OP's specific case, there are over 2 million results so we can't print them all in one column. However, running with Verbose = False, the custom combinations are generated in about 12 seconds.

Sample Image
Sample Image

Enumerating over all poker head to head hands

Your code prints the correct result, but doesn't iterate over all the cards correctly. a and c should loop up to 52. The extra hands need to be removed with an if statement:

for (int a = 0; a < 52; ++a) {
for (int b = a + 1; b < 52; ++b) {
for (int c = 0; c < 52; ++c) {
for (int d = c + 1; d < 52; ++d) {
if (c != a && c != b && d != a && d != b) {
total++;
}
}
}
}
}

This can then be modified to eliminate the duplicate hands:

for (int a = 0; a < 52; ++a) {
for (int b = a + 1; b < 52; ++b) {
for (int c = a + 1; c < 52; ++c) {
for (int d = c + 1; d < 52; ++d) {
if (c != b && d != b) {
total++;
}
}
}
}
}


Related Topics



Leave a reply



Submit