SkillAgentSearch skills...

PiedPoker

A dope library to play with poker probabilities ♣♦♥♠ https://colab.research.google.com/drive/1sLgDZRGmRojkJUEcHwz9o1j9ZN2j4l0p?usp=sharing

Install / Use

/learn @ellekdev/PiedPoker
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Pied Poker

By Ellek Linton

View As Colab Notebook

Hi! My name is Ellek, and I studied data science at UC Berkeley. I started getting into Poker during the pandemic, and wanted to create a better way to calculate poker probabilities using code.

I wrote this Python library to generate any poker probability on the fly and calculate your exact odds of hitting the hand you are targeting. For example, say you have AK suited, and the flop comes out 4AK. What are your odds of hitting a full house? What about the probability that, against 5 other players at this table, you win the hand? Well, you can calculate each of these probabilities, and nearly any other probability you want with this code!

This notebook serves as an example of how to use my pied_poker Python package to simulate poker games and probabilities. This Python package has been thoroughly unit tested and functionally tested.

This project is 100% self-written, 100% open source, and 100% free to use (excluding commercial use). For more info on the package, see the Github Project.

Let's dive right in!

First, we need to install and import the pied_poker package:

%pip install pied_poker==1.2.3

import pied_poker as pp
import numpy as np
np.random.seed(420)
Requirement already satisfied: pied_poker==1.2.3 in /usr/local/lib/python3.10/dist-packages (1.2.3)
Requirement already satisfied: joblib in /usr/local/lib/python3.10/dist-packages (from pied_poker==1.2.3) (1.3.2)
Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from pied_poker==1.2.3) (4.66.1)
Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from pied_poker==1.2.3) (1.23.5)
Requirement already satisfied: seaborn in /usr/local/lib/python3.10/dist-packages (from pied_poker==1.2.3) (0.12.2)
Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from pied_poker==1.2.3) (1.5.3)
Requirement already satisfied: matplotlib in /usr/local/lib/python3.10/dist-packages (from pied_poker==1.2.3) (3.7.1)
Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pied_poker==1.2.3) (1.2.0)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pied_poker==1.2.3) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pied_poker==1.2.3) (4.46.0)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pied_poker==1.2.3) (1.4.5)
Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pied_poker==1.2.3) (23.2)
Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pied_poker==1.2.3) (9.4.0)
Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pied_poker==1.2.3) (3.1.1)
Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pied_poker==1.2.3) (2.8.2)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas->pied_poker==1.2.3) (2023.3.post1)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib->pied_poker==1.2.3) (1.16.0)

Recently, I started playing bar poker. Initially, poker seemed like a simple game of chance—you might lose, you might win, or you might even tie. But as I played more, I realized there’s a lot more to poker beneath the surface. In every poker round, there is an element of risk, human psychology, and inherent randomness. These factors can seem dynamic and unpredictable, but a good poker player is able to effectively weigh them all to beat their opponent. I wanted to reach this level of intuition; one where I felt comfortable and confident in my betting decisions, so I made pied_poker!

The pied_poker Python package is a pure Python library to simulate poker games and probabilities efficiently. It uses an optimized Monte-Carlo style simulation.

Introduction: A Simple Example

Imagine you are starting a round of poker and you are dealt the Ace of Spades and the Queen of Spades.

p1 = pp.Player('Ellek', pp.Card.of('as', 'qs'))
p2 = pp.Player('Opponent') # We don't know the opponent's cards, so we leave that empty
print(p1, p2)
Ellek: [A♠, Q♠] Opponent: []

You bet the minimum $5 to play your hand that round because it seems like a good starting hand.

The first 3 table cards are turned: 4 of Spades, 4 of Hearts, and the 10 of Spades.

community_cards = pp.Card.of('4s', '4h', '10s')
print(f'Community cards: {community_cards}')
Community cards: [4♠, 4♥, 10♠]

Let's put this information into a "Game State", or PokerRoundResult in the pied_poker package:

round_result = pp.PokerRound.PokerRoundResult([p1, p2], community_cards)
round_result
Community Cards: [4♠, 4♥, 10♠]

     *Ellek* (winner):
          Cards: [A♠, Q♠]
          Hand: OnePair([4♠, 4♥], [A♠, Q♠, 10♠])

     Opponent:
          Cards: []
          Hand: OnePair([4♠, 4♥], [10♠])

What "outs" do we have here? We can calculate that!

round_result.outs(p1)
[Out(Flush, [2♠, 3♠, 5♠, 6♠, 7♠, 8♠, 9♠, J♠, K♠]),
 Out(TwoPair, [A♣, A♦, A♥, Q♣, Q♦, Q♥])]

We have Flush outs, if any of those Spades show up. We also have TwoPair outs, if either an A or Q shows up.

On the flipside, which possible cards could our opponents have that would beat our current hand? In pied_poker, these are called killer_cards. We can calculate those:

round_result.killer_cards(p2)
[KillerCard(ThreeOfAKind, [4♣, 4♦]), KillerCard(TwoPair, [10♣, 10♦, 10♥])]

As you can see, if our opponent has a 4, they would make ThreeOfAKind, which would beat our current hand. They could also have a 10, which would give them TwoPair, which also beats our current hand.

Let's keep going with the game! The fourth card turns, it’s the King of Spades:

community_cards.append(pp.Card('ks'))
print(f'Ellek\'s cards: {p1.cards}')
print(f'Community cards: {community_cards}')
Ellek's cards: [A♠, Q♠]
Community cards: [4♠, 4♥, 10♠, K♠]

We can once again calculate the Outs and Killer Cards for our player below to see how this card has changed things!

round_result = pp.PokerRound.PokerRoundResult([p1, p2], community_cards)
round_result
Community Cards: [4♠, 4♥, 10♠, K♠]

     *Ellek* (winner):
          Cards: [A♠, Q♠]
          Hand: Flush([A♠, K♠, Q♠, 10♠, 4♠], [])

     Opponent:
          Cards: []
          Hand: OnePair([4♠, 4♥], [K♠, 10♠])
round_result.outs(p1, False) # The "False" here indicates that we don't want to return "Outs" that are the same hand class (higher flushes)
[Out(RoyalFlush, [J♠])]

As we can see, we have hit our flush!!! We have the best possible hand on the board now! We hit the nuts. As such, we have no killer cards remaining on the current board.

However, since we have hit our beautiful nut flush, we now have the added exciting RoyalFlush draw, if the Jack of Spades shows up!

Finally, the last card turns: it’s the 10 of Hearts:

community_cards.append(pp.Card('10h'))
print(f'Community cards: {community_cards}')
Community cards: [4♠, 4♥, 10♠, K♠, 10♥]

So in summary, your cards are [A♠, Q♠], and the table cards are [4♠, 4♥, 10♠, K♠, 10♥]. Let's create one round result:

round_result = pp.PokerRound.PokerRoundResult([p1, p2], community_cards)
round_result
Community Cards: [4♠, 4♥, 10♠, K♠, 10♥]

     *Ellek* (winner):
          Cards: [A♠, Q♠]
          Hand: Flush([A♠, K♠, Q♠, 10♠, 4♠], [])

     Opponent:
          Cards: []
          Hand: TwoPair([10♠, 10♥, 4♠, 4♥], [K♠])

We still have a pretty good hand, but what cards could our opponent have that would beat us? We can calculate this again with killer cards:

round_result.killer_cards(p1)
[KillerCard(FullHouse, [10♣, 10♦, 4♣, 4♦])]

As we expect, it's now possible for our opponent to have a FullHouse which would beat our Flush, if they have either a 4 or a 10.

Your opponent raises the bet to $30, and you must decide if you want to call his bet, or fold and lose the money you’ve already contributed to the pot. If your opponent has either a 4 or a 10, they would have a Full House that would beat your Ace-high Flush. Or, they could have a worse hand than you, maybe a King-high Flush. What would you do in this situation—would you call your opponent’s raise, hoping your Flush sustains the win? Or would you fold out of fear that your opponent has the Full House?

Using the pied_poker Python package, we can calculate all of these odds!

First, lets run some simulations. Lets use this scenario and simulate it 10,000 times to see the different possible outcomes.

simulator = pp.PokerRound.PokerRoundSimulator(community_cards=community_cards,
                       players=[p1, p2],
                      total_players=2)
num_simulations = 10000

simulation_result = simulator.simulate(n=num_simulations, n_jobs=1)
100%|██████████| 10000/10000 [00:10<00:00, 971.67it/s]

Now that we have run the simulation, we can calculate any probability we want! First, let's visualize the hand type distribution for you (p1) in this setup:

simulation_result.visualize_player_hand_distribution(p1)

png

Since all of the community car

Related Skills

View on GitHub
GitHub Stars42
CategoryEducation
Updated3mo ago
Forks10

Languages

Python

Security Score

72/100

Audited on Dec 10, 2025

No findings