44

Poker Simulation with Python

 2 years ago
source link: https://towardsdatascience.com/how-to-build-a-poker-simulation-tool-with-python-449eddd59613
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Poker Simulation with Python

Source: https://unsplash.com/photos/K2PAVcngNvY

In my previous story, I showed how to score all possible hand combinations in Poker (I recommend you check it and download the code as we are going to use it here).

Now is time to actually play the game and use Python to calculate odds, expected value, and betting size.

These days most people playing Texas Hold’em have a solid preflop game. Tables with preflop odds are easy to find and rules to decide whether someone should call, raise, or fold preflop are memorized by avid online players. For example, see the table below to determine your action preflop in No-Limit Cash Games depending on your position:

1*ah1TA1-1hmJbz8JmNQ4QgA.png?q=20
how-to-build-a-poker-simulation-tool-with-python-449eddd59613
Source: Image By Author

Therefore, it seems to me, simulation tools are most useful when playing post-flop. There are many combinations that need to be calculated fast, and Python can accomplish this with the help of high-speed libraries like Numba.

Introducing Numba to speed up Python for loops

Numba allows us to compile our code by just adding a decorator. It doesn’t work with all Python code but is very useful in case you are doing for loops. I wrote an article on how to make Python super-fast (actually faster than brand-new Julia) code and Numba was the top performer library.

I also combined Numba with the lru_cache method that allows caching Python code, this optimized my code and let it run fairly quick.

In this case, we are going to iterate many times over all possible hands in Poker: that is 2,598,960 hands. The reason for this is we want to check whether these hands contain certain cards. So there is plenty of iteration here and classic Python would be painfully slow. Also, Numpy Vectorizing seems difficult because we have double for loops. So I consider this a good example to introduce you to the Numba library.

OK, having cleared this up, we can now move on to build our simulation.

Checking Combinations on the Flop

First things first: let’s model the situation when the flop comes.

Let’s call our 2 preflop cards + 3 cards in the flop the “present-cards”. These 5 cards can be used to make a hand already. But there are 2 more cards coming in the turn and river, so our final hand could contain only 4 or 3 cards from our present-cards. The final hand in the river must have a minimum of 3 cards coming from our present cards, never less than that.

Therefore, we can build all possible combinations with 3 and 4 or our present-cards that I call c3 and c4 in my script. Then we calculate the average score for all 5 cards hands containing any of these combinations. That will be our expected value for “future-cards” coming.

This value is very useful to avoid wishful thinking and understanding the reality of our situation, whether we are likely to improve our hand or not. Numbers don’t lie!

Checking Combinations on the Turn

Now the turn comes and we have 6 “present-cards”. We could build 6 different hands with these cards, one of them will be our current best hand. But once again there still one more card coming, so the final hand in the river could have a minimum of 4 cards coming from our “present-cards”.

There are 15 different 4-cards combinations to be made with our cards in the Turn. We will check the score of every 5 cards hand containing them and calculate the mean. This will be our expected value in the Turn.

Checking Value in the River

The last step is simple. We have 7 cards available which make 21 different 5 cards hands. There is no future cards here, we just pick the best one out of the 21 and that’s our final value for good or worse.

Wrapping this in a Python function

I have wrapped all of the above in a function called evaluation that takes our present cards in the flop and all combinations as arguments. It checks how many cards we have to determine if we are in the flop (5 cards), Turn (6 cards), or River (7 cards).

Then it returns “present-cards” value that I call maxi (because is our current maximum score) and “future-cards” expected value that I call mean (because it is the mean of all possible future scenarios).

The double for loops for iteration is wrapped in a Numba function as I mentioned already. The scoring method score_hands that we imported from the exercise in my previous post, is also wrapped in a cached function for best performance.

Just like this:

OK, so now we are ready to play. Let the action begin!

Playing the flop

Our script will prompt us to type in our cards in the flop. Press enter and get results for your current cards value as well as the average value that you can expect in the Turn and River with the cards you own.

Now you get prompted to type in how many players are at the table, the size of the pot, the percentile of your score, and finally the price of the bet you have to make if you wish to bet at all. Then we need to analyze what’s the best decision to make and for that purpose I created this function called “should_call”:

The code for the full flop process is this:

And now let’s run one example of our code with 11-Spades and 11-Clubs preflop. Then 5-Hearts, 6-Diamonds and 2-Diamonds in the Flop. There are 5 players in a no-limit game and we estimate the pot size at 20 $. We have bet 2 $ preflop and we have to decide if we call another bet of 2 $ in the flop.

1*TAH7zK-y0c5kVRz8JI9aOw.png?q=20
how-to-build-a-poker-simulation-tool-with-python-449eddd59613

As we can see, in this case, the expected value is positive at 2.35$ so we call.

Playing the Turn

Now the Turn comes and it’s 5-Diamonds. Similar process as done before, but with the cards in the Turn. Like so:

Our code will return this:

1*FpEaXB-ZvjYEhJQ9WPxqcQ.png?q=20
how-to-build-a-poker-simulation-tool-with-python-449eddd59613

Now we have to pairs and we have to call another bet of 4$ so we are betting 8$ in total for a pot of 20$. As we have a very strong hand, the expected value is positive at 7.34 $. Let’s suppose we call again and see the river.

Playing the River

Finally, we are dealt the river card, which is an Ace of spades. We type it in and recalculate:

1*XrssoUyNQPUBfkxueqm4eg.png?q=20
how-to-build-a-poker-simulation-tool-with-python-449eddd59613

So, we should have the same final value because our best hand didn’t change and probably we would have won the pot.

As an experiment, I just changed the players to 2 players, so you can see how the expected value goes up.

This shows us that, for the same hand, in a table of 3 players your probabilities of winning are greater than in a table of 6 players. In turn, the 6 players table will have a larger pot so this tends to level up the value.

In any case, you should set the number of players to those at the start of the hand and don’t discount players as they fold.

Alright, so that is it. Now we are ready to practice with some different hands and get recommendations as to where we should call, fold, or raise with our own Python code.

You can download the code for the full script here:

https://github.com/dirusali/pokerodds/blob/release-1.0/poker.py

This is how Poker software works and coding it is very helpful to understand why some decisions are made and what we should take into account to make a value bet.

I hope you guys enjoyed it. Happy coding!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK