0

I'm trying to make a list of all possible 5 card poker hands to use in some computations (that may be slow but is preferably somewhat speedy). Now to get a list, I wrote the following code:

import itertools

# All possible Cards:
cards = ['2s', '2h', '2d', '2c', '3s', '3h', '3d', '3c', '4s', '4h', '4d', '4c', '5s', '5h', '5d', '5c', '6s', '6h', '6d', '6c', '7s', '7h', '7d', '7c', '8s', '8h', '8d', '8c', '9s', '9h', '9d', '9c', 'Ts', 'Th', 'Td', 'Tc', 'Js', 'Jh', 'Jd', 'Jc', 'Qs', 'Qh', 'Qd', 'Qc', 'Ks', 'Kh', 'Kd', 'Kc', 'As', 'Ah', 'Ad', 'Ac']

hands = []

# Collect all non-trivial cartesian products
for element in itertools.product(cards,cards,cards,cards,cards):
    c1,c2,c3,c4,c5 = element
    if c1 != c2 or c1!=c3 or c1!=c4 or c1!=c5 or c2 != c3 or c2 != c4 or c2 != c5 or c3 != c4 or c3 != c5 or c4 != c5:
        hands.append([c1,c2,c3,c4,c5])
# Sort all elements and delete duplicates
for x in hands:
    x.sort()
hands = [tuple(x) for x in hands]
hands = list(set(hands))
# Convert hands back to a list
hands = [list(x) for x in hands]

# Verify result
print(str(len(hands)))

But this runs out of memory before it's completed (over 11 gigs of RAM). I'm trying to use that list so I can exhaustively test against the set of all possible hands when I try to put 2 hands up against one another.

Does anyone know how I could make this code better?

Mitchell Faas
  • 430
  • 6
  • 19
  • Whenever you find yourself thinking "make a list of all possible [thing]", you should first consider whether it's even the slightest bit reasonable to stuff all possible [thing] in memory or go over all possible [thing] to accomplish your task. It's usually a bad idea. – user2357112 Jul 25 '17 at 16:46
  • You don't need a list of all possible hands to compare two hands against each other. – user2357112 Jul 25 '17 at 16:46

3 Answers3

2

Python actually comes with some batteries included stuff for making combinations.

Here is the function That will do that for you.

cards = ['2s', '2h', '2d', '2c', '3s', '3h', '3d', '3c', '4s', '4h', '4d', '4c', '5s', '5h', '5d', '5c', '6s', '6h', '6d', '6c', '7s', '7h', '7d', '7c', '8s', '8h', '8d', '8c', '9s', '9h', '9d', '9c', 'Ts', 'Th', 'Td', 'Tc', 'Js', 'Jh', 'Jd', 'Jc', 'Qs', 'Qh', 'Qd', 'Qc', 'Ks', 'Kh', 'Kd', 'Kc', 'As', 'Ah', 'Ad', 'Ac']

hands = itertools.combinations(cards, 5)

for hand in hands:
  print(hand)
Adam LeBlanc
  • 932
  • 7
  • 21
1

You are producing ~52^5 = ~380 million hands, and trying to sort them. It is going to take a lot of memory. You need to fix the logic for asking sure each element in each hand is unique. What you currently have will only remove ones where they are all the same.

c1, c2, c3, c4, c5 = "2s", "2s", "2s", "2s", "3s"
print(c1 != c2 or c1!=c3 or c1!=c4 or c1!=c5 or c2 != c3 or c2 != c4 or c2 != c5 or c3 != c4 or c3 != c5 or c4 != c5)
>>>True

You could either replace all the ors with ands, or you could just test if the set of the elements is equal to the elements themselves, which will eliminate hands with duplicates.

c1, c2, c3, c4, c5 = "2s", "2s", "2s", "2s", "3s"
print(list(set([c1,c2,c3,c4,c5])).sort() == [c1,c2,c3,c4,c5].sort())
>>>False
c1, c2, c3, c4, c5 = "2s", "3s", "4s", "5s", "6s"
print(list(set([c1,c2,c3,c4,c5])).sort() == [c1,c2,c3,c4,c5].sort())
>>>True

That will cut the number of hands down to 52 choose 5 = ~2.6 million, which is much more manageable.

Sam Craig
  • 875
  • 5
  • 16
1

First, the function you are trying to create already exists: itertools.combinations. Second, try to structure your code so that you can iterate over all possible hands without putting them all in memory simultaneously.

Here is a short program that prints all possible hands, with duplicate hands removed, but never creates an in-memory list of all possible hands:

import itertools
cards = [''.join(x) for x in itertools.product('23456789TJQKA', 'shdc')]

for hand in itertools.combinations(cards, 5):
    print (hand)

If you actually need the entire list to be in memory, try:

import itertools
cards = [''.join(x) for x in itertools.product('23456789TJQKA', 'shdc')]
big_list = list(itertools.combinations(cards, 5))
print len(big_list)
Robᵩ
  • 163,533
  • 20
  • 239
  • 308