How to deal cards according to probabilities?

Viewed 112

Moved to stats.stackexchange

I am trying to write a function that deals cards to players given a probability distribution. This can be thought of as a dealer who is cheating and wants to give certain cards to certain players but doesn't want to be obvious.

For example with a three card deck and three players:


Ace King Queen
Player 1 0% 66% 33%
Player 2 33% 33% 33%
Player 3 66% 0% 33%

Choosing a card based on weights is not the problem. The problem is that when a card is chosen then that card cannot be at another player.

Choosing one by one can lead to situations when the remaining player has 0% probability to get the remaining card. In the above example - what if Player 1 gets a Queen, Player 2 gets an Ace. Then Player 3 cannot get any card as his King probability is 0%.


One way I tried is to deal the cards per player. Then check if there are duplicates and if there are I deal again till there are no duplicate cards. The resulting distribution does not follow what I want.

The reason for this (in the example above) is that the re-dealing would happen more often for Player 1 getting Queen because the chance of a duplicate in that case is 66% unlike when Player 1 gets a King (33%). This skews the resulting distribution.


Another way that I tried is to deal Player 1's card. Then remove that from the possible Player 2 cards and deal a card out of that for Player 2. The card for player 3 is the remaining card. This I saw is clearly stupid because Player 3 even had Kings which he should have with 0% probability.

Here is the code for the second version I mentioned:

import random

# returns a list of three cards:
# 0 is an Ace,  1 is a King and 2 is a Queen
def sample(probabilities):
    p1_card = random.choices([0, 1, 2], weights=probabilities[0])[0]

    p2_possible_cards = [0, 1, 2]
    p2_weights = probabilities[1][:]

    p2_possible_cards.pop(p1_card)
    p2_weights.pop(p1_card)

    p2_card = random.choices(p2_possible_cards, weights=p2_weights)[0]

    if 0 not in [p1_card, p2_card]:
        p3_card = 0
    elif 1 not in [p1_card, p2_card]:
        p3_card = 1
    else:
        p3_card = 2

    return [p1_card, p2_card, p3_card]


probabilities = [
    [0.0, 0.666666, 0.333333],
    [0.333333, 0.333333, 0.333333],
    [0.666666, 0.0, 0.333333],
]

distribution = [
    [0.0, 0.0, 0.0],
    [0.0, 0.0, 0.0],
    [0.0, 0.0, 0.0],
]

for _ in range(100_000):
    for card, dist in zip(sample(probabilities), distribution):
        dist[card] += 1

distribution = [[card / 100_000 for card in player] for player in distribution]

# distribution is:
# [
#    [0.0    , 0.66734, 0.33266],
#    [0.50087, 0.16556, 0.33357],
#    [0.49913, 0.16710, 0.33377],
# ]
# which is not even close to probabilities
1 Answers

I think you have done a very good observation with the following:

Another way that I tried is to deal Player 1's card. Then remove that from the possible Player 2 cards and deal a card out of that for Player 2. The card for player 3 is the remaining card. This I saw is clearly stupid because Player 3 even had Kings which he should have with 0% probability.

And I would even say it's not stupid at all. You will have to deal with the fact that every card can only be dealt exactly one time (no less and no more). Starting at player 1, everything is fine and she gets a king with 66% probability and a queen with 33% probability. Then when going to player two, the distribution for all three cards might be uniform, but the supply isn't. It is not possible to deal a king with 33% probability if the king isn't available.

The situation for player two is conditional on the outcome of player one. I think in this case it's most clear when you simply consider all possible cases:

  1. king, 2) ace
  2. king, 2) queen
  3. queen, 2) ace
  4. queen, 2) king

Draw this like a tree and put probabilities on all branches, you will then come to the conclusion that the following probabilities apply and will give you a uniform distribution of the three cards for player two:

deal player two ace, given that player one has king: 1/2
deal player two queen, given that player one has king: 1/2
deal player two ace, given that player one has queen: 0
deal player two king, given that player one has queen: 1

probability for queen: (2/3) * (1/2) = (1/3)
probability for king: (1/3) * 1 = (1/3)
probability for ace: (2/3) * (1/2) + (1/3) * 0 = (1/3)

You can add player three in a similar fashion, the problem just becomes bigger.

EDIT: The probability you are looking for in your question is infeasible. Player three can not have a 0% chance of getting a card when there is a positive chance that this card is the only one left to give player three. The only way to avoid this is to change the order in which you deal cards. But taking into the account 'dealer' context, there is usually no free choice in order.

Related