patternpythonMinor
Poker probabilities finder
Viewed 0 times
pokerprobabilitiesfinder
Problem
This code finds the probabilities of the various scores in Poker. It uses a Monte Carlo approach, in which, two million (\$2 \times 10^{6}\$) hands are simulated and evaluated, not an exhaustive search.
According to Wikipedia, my results are accurate.
I strived to avoid over-engineering, where the only tricky part is
I am interested in performance improvements only if they do not hurt readability and straightforwardness.
An example output is:
The code:
```
from __future__ import division
from collections import namedtuple, Counter
import doctest
import random
import time
CARDS_PER_HAND = 5
VALUES = 13
KINDS = 4
ACCURACY = 2 * 10 ** 6
Card = namedtuple("Card", ["value", "kind"])
def all_equal(lst):
"""
>>> all_equal([1,1,1,1])
True
>>> all_equal([1,2,3])
False
"""
return len(set(lst)) == 1
def couples(lst):
"""
>>> couples([1,5,7])
[[1, 5], [5, 7]]
"""
return [ [curr, lst[index + 1]]
for index, curr in enumerate(lst[:-1])]
def one_by_one_increasing(lst):
"""
>>> one_by_one_increasing([5, 6, 7, 8])
True
"""
return all(nexxt == previous + 1
for previous, nexxt in couples(lst))
def most_common(lst):
"""
>>> most_common([1,2,2,2,3])
2
"""
return Counter(lst).most_common()[0][0]
def most_common_count(lst):
"""
>>> most_common_count([4,4,4,1,1])
3
>>> most_common_count([7,3,1,7,8])
2
"""
return lst.count(most_common(lst))
def first_true(arg, funcs):
"""
>>> def false(n): return False
>>> def even(n): return n % 2 == 0
>>> first_true(14, [false, even
According to Wikipedia, my results are accurate.
I strived to avoid over-engineering, where the only tricky part is
poker_value as it uses a bit of metaprogramming, but it was necessary to avoid duplication.I am interested in performance improvements only if they do not hurt readability and straightforwardness.
An example output is:
Poker probabilities:
('nothing', 50.1837)
('pair', 42.1968)
('two_pair', 4.77195)
('three_of_a_kind', 2.18145)
('straight', 0.3568)
('flush', 0.198)
('full_house', 0.08485)
('four_of_a_kind', 0.02505)
('straight_flush', 0.0014)
Time taken: 107.4311831
The code:
```
from __future__ import division
from collections import namedtuple, Counter
import doctest
import random
import time
CARDS_PER_HAND = 5
VALUES = 13
KINDS = 4
ACCURACY = 2 * 10 ** 6
Card = namedtuple("Card", ["value", "kind"])
def all_equal(lst):
"""
>>> all_equal([1,1,1,1])
True
>>> all_equal([1,2,3])
False
"""
return len(set(lst)) == 1
def couples(lst):
"""
>>> couples([1,5,7])
[[1, 5], [5, 7]]
"""
return [ [curr, lst[index + 1]]
for index, curr in enumerate(lst[:-1])]
def one_by_one_increasing(lst):
"""
>>> one_by_one_increasing([5, 6, 7, 8])
True
"""
return all(nexxt == previous + 1
for previous, nexxt in couples(lst))
def most_common(lst):
"""
>>> most_common([1,2,2,2,3])
2
"""
return Counter(lst).most_common()[0][0]
def most_common_count(lst):
"""
>>> most_common_count([4,4,4,1,1])
3
>>> most_common_count([7,3,1,7,8])
2
"""
return lst.count(most_common(lst))
def first_true(arg, funcs):
"""
>>> def false(n): return False
>>> def even(n): return n % 2 == 0
>>> first_true(14, [false, even
Solution
Your code looks good and the logic is well separated in testable (and tested) functions.
A few details :
-
Maybe it would make sense for
I'll try to continue.
A few details :
-
Maybe it would make sense for
all_equal(lst) to return True for an empty list (just like the all builtin returns True for empty iterable). You'd just need to replace == 1 by
-
In couples, you are using explicitely the index to iterate over consecutive arrays. You'll find various other ways to do so. I'll let you pick the one you prefer (after performing some benchmark if needed). Also, because of the way you use it, there might not be a need for returning a newly constructed list, an iterable would be enough.
-
Your implemement of most_common should pass 1 as a parameter to most_common so that it doesn't generate the whole list so that you are mostly ignoring.
-
Your implementation of most_common_count is not really efficient : the most_common() function already returns the count and you are simply ignoring it.
I think the right way to do it would be to have a most_common() function returning a tuple (item, count)`. Also you should probably handle the cases where different items are the most common.I'll try to continue.
Context
StackExchange Code Review Q#97626, answer score: 4
Revisions (0)
No revisions yet.