Open Side Menu Go to the Top
Register
[Python 3] Holdem Hand v Hand Equity Calculator :confused: [Python 3] Holdem Hand v Hand Equity Calculator :confused:

05-25-2019 , 07:19 PM
Hey all,

I've been searching this forum and the net for a little while and I haven't come up with something good.

I'm looking for a Python 3 Linux/Mac compatible hand v hand equity calculator.

I don't want to work in C / C++ or write something myself if I don't have to.

From what I've seen, there are python 2 32bit libraries like `poker-eval` (used eg in Will Tipton's series) but I have to work in 64bit python 3 cloud environment.


I can't get pokersleuth to work either. Decues / treys do not do equity calculations (eg https://github.com/ihendley/treys)

Advice greatly appreaciated.


Thanks,
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-25-2019 , 08:51 PM
I have never used Treys but it seems like it would be trivially easy to do equity calculations with it. Equity calculations are nothing more than trying a bunch of random boards and counting how many times you win. If there aren't too many possible boards you can also enumerate them and count wins (and count ties as 1/n where n is the number of players tying)
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-26-2019 , 10:12 PM
Yea thanks I'll think I'll try that then.


Perhaps I'll come back with an update.
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-27-2019 , 06:37 PM
Hey all, so I wrote some simple python code to do this.

it's quick and dirty, takes about 1s to run 10,000 All-in heads up simulations and return the % that hand1 wins. This simple method misses draws but is still accurate enough for my applications.

If I (or anyone here) can speed this up substantially, in the future, maybe we will compute all of the hand v hand equities accurately and post here in a python friendly format.

All the public data I can find on the internet are about Heads up all v a random hand, whereas we're looking for all of the data hand v hand.



Code:
# Estimate Equities Headsup All in Texas Holdem
# Python3


import treys # https://github.com/ihendley/treys
from treys import Deck, Card, Evaluator
from random import shuffle
from multiprocessing import Pool # to speed up calculations


# Set some params for the equity calculation later 
POOL_SIZE = 4
NUM_SIMULATIONS = 10000


# We need only one instance of the Evaluator
# use the Evaluator to check the winner once the board has been dealt
evaluator = Evaluator()

def _deal_random_board_evaluate(hands):
    '''
    Given two Texas Holdem Starting hands, run out one five card board and check the winner
    
    :param hands: string like 'Ah2dKdKc'   
    :returns: True if player1_hand wins else False
    
    '''
    
    # instantiate a new deck and shuffle it
    deck = Deck().GetFullDeck()
    shuffle(deck)
    
    # create the players' hands and pop them from the deck
    # so that they do not conflict with the board
    # eg assert len(deck) == 48
    
    player1_hand= [deck.pop(deck.index(Card.new(hands[:2]))), deck.pop(deck.index(Card.new(hands[2:4])))]
    player2_hand= [deck.pop(deck.index(Card.new(hands[4:6]))), deck.pop(deck.index(Card.new(hands[6:])))]
    

    board = deck[:5]
    
    
    # returns TRUE if player1_hand is the winning poker hand
    # in treys, the lower the number the better the hand
    
    return evaluator.evaluate(board, player1_hand) < evaluator.evaluate(board, player2_hand)


def estimate_equity(hands,num_simulations=NUM_SIMULATIONS, pool_size=POOL_SIZE):
    ''' Estimate the Heads up All in Equity of a given Texas Holdem Starting Hand against one other hand
    
    :param hands: string of the two starting hands with no spaces, eg 'AhAdKcKd'
    :param num_simulations: integer, the number of simulations to run, one simulation deals one 5 card board and checks the winner
    :param pool_size: integer the number of processes to start via multiprocessing
    
    
    :returns: float the equity estimate
    
    '''
    pool = Pool(pool_size)
    results = pool.map(_deal_random_board_evaluate, [hands]*num_simulations)
    
    return sum(results)/num_simulations

eg if you save the code in a file run_simulator.py

>> from run_simulator import estimate_equity
>> estimate_equity('AdAhKcKd')
>> # 0.8199


---- okay, there is something wrong with how I'm multithreading here.... will update with fix lol

Last edited by PajamaBottoms; 05-27-2019 at 06:55 PM.
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-27-2019 , 07:55 PM
okay this is working

Code:
# Estimate Equities Headsup All in Texas Holdem
# Python3
# use eg estimate_equity.py AhAdKhKd 100 
# 0.81


import treys # https://github.com/ihendley/treys
from treys import Deck, Card, Evaluator
from random import shuffle
import sys
from multiprocessing import Pool, Process # to speed up calculations


# Set some params for the equity calculation later 
POOL_SIZE = 4
HANDS = str(sys.argv[1])
NUM_SIMULATIONS = int(sys.argv[2])



# We need only one instance of the Evaluator
# use the Evaluator to check the winner once the board has been dealt
evaluator = Evaluator()

def _deal_random_board_evaluate(hands):
    '''
    Given two Texas Holdem Starting hands, run out one five card board and check the winner
    
    :param hands: string like 'Ah2dKdKc'   
    :returns: True if player1_hand wins else False
    
    '''
    
    # instantiate a new deck and shuffle it
    deck = Deck().GetFullDeck()
    shuffle(deck)
    
    # create the players' hands and pop them from the deck
    # so that they do not conflict with the board
    # eg assert len(deck) == 48
    
    player1_hand= [deck.pop(deck.index(Card.new(hands[:2]))), deck.pop(deck.index(Card.new(hands[2:4])))]
    player2_hand= [deck.pop(deck.index(Card.new(hands[4:6]))), deck.pop(deck.index(Card.new(hands[6:])))]
    

    board = deck[:5]
    
    
    # returns TRUE if player1_hand is the winning poker hand
    # in treys, the lower the number the better the hand
    
    return evaluator.evaluate(board, player1_hand) < evaluator.evaluate(board, player2_hand)


    
    
if __name__ == '__main__':
    
    data = [HANDS]*NUM_SIMULATIONS
    
    with Pool(processes=POOL_SIZE) as pool:
        results = pool.map(_deal_random_board_evaluate, data)
        
        print(sum(results)/NUM_SIMULATIONS)
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-27-2019 , 08:30 PM
Lol hey I'm making some big mistakes not counting the draws. I'll be back later :/
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-28-2019 , 08:56 AM
What do you mean by "not counting the draws"?
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-28-2019 , 08:56 AM
Oh you mean ties. Yeah you definitely have to do that.
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-28-2019 , 11:42 AM
I made some minor modifications that made it a little faster, and also handled ties. But it's not much of a speedup - like 3.25s instead of 5s.

Mostly what I'm doing is dividing the work into bigger chunks so that you don't have to initialize the deck and player hands every iteration.

Also note that it does only an approximate of the number of asked for iterators, because it divides it into chunks of 8*POOL_SIZE (8 is abitrary, actually I tried a bunch of numbers from 1-10 and they were all about the same)

With 4 members in the pool this would divide it into 32 chunks, each n/32 large. So if n=1000, each chunk would be 31 iterations, so your total number would be 992 iterations. I believe I've properly accounted for this, and if N is large it doesn't really make much difference. You could make it exact without too much trouble if you like.

Code:
import treys # https://github.com/ihendley/treys
from treys import Deck, Card, Evaluator
from random import shuffle
import sys
from multiprocessing import Pool, Process # to speed up calculations


# Set some params for the equity calculation later 
POOL_SIZE = 4
HANDS = str(sys.argv[1])
NUM_SIMULATIONS = int(sys.argv[2])

# We need only one instance of the Evaluator
# use the Evaluator to check the winner once the board has been dealt
evaluator = Evaluator()


def _deal_random_board_evaluate(a):
    hands, count = a

    wins = 0
    deck = Deck().GetFullDeck()

    player1_hand = [deck.pop(deck.index(Card.new(hands[:2]))), deck.pop(deck.index(Card.new(hands[2:4])))]
    player2_hand = [deck.pop(deck.index(Card.new(hands[4:6]))), deck.pop(deck.index(Card.new(hands[6:])))]

    for i in range(count):
        shuffle(deck)
        diff = evaluator.evaluate(deck[:5], player1_hand) - evaluator.evaluate(deck[:5], player2_hand)
        wins += (diff < 0) if diff else 0.5

    return wins



if __name__ == '__main__':
    parts = POOL_SIZE*8
    data = [(HANDS, int(NUM_SIMULATIONS/parts))]*parts
    real_num_sims = int(NUM_SIMULATIONS/parts)*parts

    with Pool(processes=POOL_SIZE) as pool:
        total_wins = sum(pool.map(_deal_random_board_evaluate, data))

        print(total_wins/real_num_sims)
        
        print(total_wins/NUM_SIMULATIONS)
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-29-2019 , 06:00 AM
What's the bottleneck for these calculations?

Given that hand evaluators run beyond 100mio evaluations per sec per core the reported speeds here look quite off.

My Python is really poor, but some thoughts: It looks like you are shuffling full deck lists for every sample? Maybe try using regular arrays instead, and don't re-shuffle the whole deck if you only need 9 cards.
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-29-2019 , 09:56 AM
Quote:
Originally Posted by plexiq
What's the bottleneck for these calculations?

Given that hand evaluators run beyond 100mio evaluations per sec per core the reported speeds here look quite off.
It's pure python, and probably it's literally doing actual hand evaluation rather than a series of lookup tables. Like, it's probably figuring out "oh, this hand is 2 pair, Ks and 4s"

Most of the fast hand evaluators use a series of lookup tables
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-29-2019 , 12:28 PM
You can check out this open source project: https://github.com/JBielan/py_ev .

I decided to do something useful while brushing up programing skills. It's fully written and tested in Python 3. It runs 14k simuls per second at the moment and optimizations should be easily doable as it's version 0.0.1.

Feel free to join the project and contribute.
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-29-2019 , 08:14 PM
Hey gents,

So I've run the calculations for all matchups at 10k simulations = ~ 270,725 * 10,000 = (52 choose 4) * 10k calculations, which took over a day

We also could have probably sped this up by accounting for isomorphisms (eg using the same estimate for all KK v AA with no suit domination instead of calculating every combo...)

I have generated a ~5MB CSV like :

hand1, hand2, equity_hand_1
KcKs,AcAs,0.1655
KcAh,AdAc,0.06565
KcAh,AdAs,0.0723
KcAh,AcAs,0.06505
KcAd,AcAs,0.06755
KsAh,AdAc,0.0776
KsAh,AdAs,0.0645
KsAh,AcAs,0.062
KsAd,AcAs,0.06395
AhAd,AcAs,0.50005

checking some randomly selected hands and values manually via the Cardplayer tool here: https://www.cardplayer.com/poker-too...r/texas-holdem
gave great results

I'll update this thread with a public link to that data if you want it


THANKS for the updates to the code and for the intro to the py_env project, perhaps I will collaborate more with you all there. I haven't checked out this part of 2p2 so I'm glad to be here.
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
05-29-2019 , 08:51 PM
and FCD, dude, you should check out Treys and Deuces which are waaay faster than what you have here and Decues at least is also pure python.


checking your repo, the idea is cool of course, but I would say don't reinvent the wheel and it'd probably be better for the community if we made treys better instead of trying to make that project as good as treys.

the whole part checking for each of the hands `is_pair` , `is_two_pair` etc is too painful

also there are lots of small things you can do. Why do you need a nested for loop when creating the deck?

Code:
# Speed test I just ran for you


# your function in py_ev
def build_deck():
    new = []
    for f in range(2, 15):
        for s in range(1, 5):
            new.append((f, s))
    return new

# an alternative 
def new_deck():
    return list(itertools.product(range(2,15), range(1,5)))
    # you might not even need to call list() here
    # depending on how you intend to use this


%timeit build_deck()

# 10000 loops, best of 3: 20.5 µs per loop

import itertools # ships with python
%timeit new_deck()

# 100000 loops, best of 3: 6.95 µs per loop
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote
06-04-2019 , 09:10 AM
PajamaBottoms - Thanks for the feedback. It's pure fun for me and I do it mostly to train programming skills. I'm not sure why you say Tray is so much faster? It looks like Tray has 15k/sec with a whole bunch of optimizations and my initial algorithm has 14k?

What's also very important, Tray/Dueces aren't tested at all so you can't be sure there won't be bugs after updates.

Quote:
the whole part checking for each of the hands `is_pair` , `is_two_pair` etc is too painful
Yeah, it looks like that but it took like 6h to write all of this together with tests and it performs the same as other Python evaluators without optimizations. So it sounds like not that bad deal.

Quote:
Why do you need a nested for loop when creating the deck?
It was the easiest way to do at the point I was writing the code and it executes only once in __init__() function so it doesn't have any impact on performance.

As I said, it's only fun and learning for me - both coding and developing open-source projects. That's why I'd rather prefer to build something with good fundamentals from zero.

EDIT: From what I see Deuces is for Python 2.x and Treys doesn't even have equity method. I don't want to convince you which one is better. Both projects are written for fun and aren't commercial so the one with better people, still motivated to write some free code, will be better to join.

Last edited by FCD; 06-04-2019 at 09:17 AM.
[Python 3] Holdem Hand v Hand Equity Calculator :confused: Quote

      
m