4

I am writing a poker application and trying to figure out how to deal with split pots and side pots

There are four rounds of betting and each round of betting can have multiple orbits

Can only bet the chips in front of you
So if a player is all in a side pot is created

Hands can tie - in which case the pot is split
If it does not spit evenly the 'last aggressor (raise)' gets the odd chip(s)

If you are raised you must call or fold
If you fold you lose your bets even if the hand wins
You cannot just cap you betting and create a side pot
You only create a side pot if you are all in

PlayerA all in 40 Win
PlayerB 80 second
PlayerC 80 last

Player A would take 120 (win 80 as 40 was his money in)
Player B would take 80

But you don't know the win order until the end
And when PlayerA went in you don't know how many people are going to call

What could be good algorithm for this?

This code is C# but really just looking for an approach.

My initial thought is to just record all the betting for each player
street, orbit, bet

Where that gets messy is that in a single orbit you could have multiple players all in for different amounts (bet)

And a different amount is not just all in
Player could be raised and then fold
In that case you know they lose but you still don't know who they lose to

There are rarely more than 3 orbits in a round
You could assume there would never be more than 10 as with min raise players would run out of chip

12
  • 3
    You can store the bets, who made them, and whether they went all in when the players make the bets. Preserve this data until the game is decided. And then distribute the pot according to the rules. So not having the information until the game is decided does not have to be a problem. Commented May 5, 2016 at 14:28
  • 1
    To add to @KaspervandenBerg's comment, in business applications, one approach to persistence is called Event Sourcing. The idea is that instead of trying to maintain the current state from change requests, which are discarded after applied, instead the change requests are directly persisted in an events stream such as an append-only log. There are some practical advantages of this (especially when it comes to restarting a failed process), and it looks a bit like what you might need.
    – Erik Eidt
    Commented May 5, 2016 at 14:36
  • @KaspervandenBerg Yes that was my thought. Looking for more detail and a chance someone had actually done this.
    – paparazzo
    Commented May 5, 2016 at 14:39
  • 1
    I don't get the close based on debugging or writing existing code. There is no existing code for split pots. If I posted on SO it would get closed for not code.
    – paparazzo
    Commented May 5, 2016 at 17:04
  • 1
    @Paparazzi N.B. there are four rounds in hold 'em - pre-flop, post-flop, turn (4th street) and river (5th street).
    – Robbie Dee
    Commented May 5, 2016 at 17:09

5 Answers 5

1

Here is a working code to create and distribute winnings from side-pots.

class Player:
    def __init__(self, l, i, hs):
        self.live = l #False
        self.invested = i #0
        self.hand_strength = hs #100
        self.result = 0

def distribute(pot, players):
    for p in players:
        p.result= -p.invested # invested money is lost originally

    # while there are still players with money
    # we build a side-pot matching the lowest stack and distribute money to winners
    while len(players)>1 :
        min_stack = min([p.invested for p in players])
        pot += min_stack * len(players)
        for p in players:
            p.invested -= min_stack
        max_hand = max([p.hand_strength for p in players if p.live])
        winners = [p for p in players if p.hand_strength == max_hand if p.live]
        for p in winners:
            p.result += pot / len(winners)
        players = [p for p in players if p.invested > 0]
        pot = 0
    if len(players) == 1:
        p = players[0]
        # return uncalled bet
        p.result += p.invested

This example shows a case where there are 5 players and the starting pot is 100. The main pot is split between player who are allin for 20 and 80. One player has folded after investing 50 and his best hand is wasted. One player has overbet all others and his bet is returned to him while he loses only the amount matched by the other players (80)

players = [Player(True, 20, 100),  Player(False, 50, 200),  Player(True, 80, 90),  Player(True, 80, 100), Player(True, 1000, 0)]
distribute(100, players)
for p in players:
    print(p.result)
#80.0
#-50
#-80
#230.0
#-80    
0
3

In my code, after every player has spoken, for every stake in the set of stakes of the players who are still in play, i create a pot. Then i order the pots from the smallest (that will be the main pot) to the highest (side pots). The side pots are represented as a list, in this format: [ needed stake, pot amount].

For the main pot, the "pot amount" will be equal to: "needed stake" * number of players (including the ones who folded) whit a stake equal or higher than "needed stake".

For the remaining pots, the "pot amount" will be equal to: ("needed stake" - needed stake of the pot preceding this one in the list) * number of players whit a stake equal or higher than "needed stake"

1

The basic algorithm is the dead chips (folds) + the minimum committed chips are distributed among the winners of the hand (main pot). If after this, there are still chips left in the pot, the process is repeated (for every side pot).

So let's say at the end of a hand there were three players all-in and $300 in dead chips:

P1 shoved $50, P2 shoved $100 and P3 shoved $150.

Scenario 1

If the hands were equal (3 way pot), everyone would get $150 in the first iteration.

In the next, P2 & P3 would collect an additional $50. In the final iteration, P3 would collect an additional $50.

So the winnings would be:

P1 $150

P2 $200

P3 $250

Scenario 2

Let us assume here that P1 wins.

P1 collects $450 (his $50 and $50 each from P2 & P3 + $300 dead chips).

In the next iteration, let's say neither hand wins outright (board flush). P2 would collect side pot 1 ($50) and P3 would collect side pot 2 ($100).

10
  • I am aware of the rules of poker and I don't have ante in my game. The question is how to create an algorithm.
    – paparazzo
    Commented May 5, 2016 at 15:51
  • See paragraph in bold - I've taken out the ante bit. Are you coding a particular poker variant (e.g. seven card stud, Omaha or hold 'em etc) or are you writing your own?
    – Robbie Dee
    Commented May 5, 2016 at 16:27
  • Texas Holdem and yes I am writing a program. If that an algorithm then I don't follow. It is not possible to have no winners. Thanks for trying to help me.
    – paparazzo
    Commented May 5, 2016 at 16:43
  • Sorry, I meant winner in that particular iteration. I've added another scenario to clarify.
    – Robbie Dee
    Commented May 5, 2016 at 16:49
  • Thanks again for trying to help but again I am not asking about the rules of poker. If that bold paragraph defines an algorithm then it is lost on me.
    – paparazzo
    Commented May 5, 2016 at 16:59
1

Only track total bet by player and if they are folded or not

1) determine minimum bet from all player in the pot
and player not folded

2) remove that amount from the every player (including folded) bet
and sum it into a side-pot

3) based on hand strength divvy up that side pot to player stacks
if a split (tie) and there are odd chips then assign my hand position at the table

4) reset side-pot to zero (plus left over)

5) go to 1) if any player any player has any bet left
(a hand cannot end with every hand folded)

7
  • 1
    Looks like I don't need to track last aggressor. Just split any left over by the order in the hand. That is how some of the existing commercial betting sites do it.
    – paparazzo
    Commented May 5, 2016 at 18:58
  • That is more or less it - step 1 is initially the main pot and includes dead chips (players who have folded). Odd chips typically go to the first winner to the dealer's left.
    – Robbie Dee
    Commented May 5, 2016 at 19:46
  • @RobbieDee This approach is not creating initial pots and side pots. Split the main pot and side pots without defining an algorithm for creating the pots is not an algorithm.
    – paparazzo
    Commented May 5, 2016 at 19:49
  • I wouldn't get hung up on the terminology. If you find it easier to consider everything to be a side pot then fair enough.
    – Robbie Dee
    Commented May 5, 2016 at 19:53
  • 1
    The principle is the same whether you do it on the fly to visually display the side pots or whether you do it at the end. I did mine at the end initially and was worried I'd calculated it wrong and did it on the fly too as a sense check - exactly the same algorithm.
    – Robbie Dee
    Commented May 5, 2016 at 20:12
0

First determine if the round of betting has finished. i.e. all players have acted, AND EITHER all remaining players have met the price (the biggest bet) OR they have gone all-in. Only if the round of betting has finished do you start adding chips to pots.

Algorithm:

Each player has a stack, and a hasBet amount, which is the amount of money they're betting before it gets added to a pot.

  1. Take the lowest hasBet

  2. For every player left in the hand, add that amount to the pot, and subtract it from the player's hasBet

  3. Are there at least 2 players left with hasBet > 0?

YES: start a new pot, go to (1)

NO: go to (4)

  1. Is this an all-in/cards-up situation? (i.e. all players are all-in, or all players are all in except one, so there are no more betting rounds).

YES: return any remaining hasBet chips to that player, deal all the remaining cards, and determine winners (multiple pots can mean multiple winners).

NO: deal the next card and move to the next round.

Example (python)

if all_in_situation:
    add_chips_to_pot()
    cards_up_scenario()  # no more betting, deal all remaining cards
elif all_players_have_acted and all_players_have_met_price_or_shoved:
    add_chips_to_pot()
    move_to_next_stage()   # stage being flop, turn, etc
else:
    increment_action()     # action moves on to the next player


def add_chips_to_pot(self):

    lowest_bet = work_out_lowest_bet() # omitted for brevity

    current_pot_index = len(self.pots) - 1   # i.e. if there are 2 pots, the one we want is at index 1
    
    for player in self.players:
        if player.has_bet == 0:
            continue
        self.pots[current_pot_index].amount = self.pots[current_pot_index].amount + lowest_bet
        self.pots[current_pot_index].players.append(player)
        player.has_bet = player.has_bet - lowest_bet

    players_with_hasbet_remaining = work_this_out() # omitted for brevity

    if players_with_hasbet_remaining > 1:
        self.pots.append(Pot())
        self.add_chips_to_pot()
    else:
        return

..where self.pots is a list of Pots, and a Pot has 2 properties: the pot amount and a list of players that are in that Pot, which we need when determining the winner of each pot. You can have whatever data structures you like to achieve the same thing.

Split pots

You'll need a way of determining hand strength, which is beyond the scope of this question. To handle split pots we can say that each Pot has a list of winners.

def determine_winners(self):  

    for pot in self.pots:

        winners = []     # multiple winners if split pot  
        winning_score = 0
        for player in pot.players:
            if player.score == winning_score:
                winners.append(player)
            elif player.score > winning_score:
                winners = []
                winning_score = player.score
                winners.append(player)

        number_of_winners = len(pot.winners)
        for winner in pot.winners:
            winner.stack = winner.stack + (pot.amount / number_of_winners)  # division assumes ints, not decimals
            # return any spare chips from a split pot to the player in earliest position
            spare = pot.amount % number_of_winners
            self.players[0].stack = self.players[0].stack + spare

Note here that I'm returning spare chips left over from the split to the player in earliest position, which I believe is the common rule, but you can do whatever you want with them.

Not the answer you're looking for? Browse other questions tagged or ask your own question.