Probability, Play, And Python: The Math Of “Left Center Right” (Part One)
We’re At A Table
You, me, and at least one other player are sat at a table. We all have three tokens. There are also three dice. We go around clockwise rolling the dice, and passing our tokens in a fashion dictated by the dice: “L” or “R” for passing to the player on your left or right, “C” for passing tokens to a central pot, and a simple dot that means “Do nothing.” We carry on this probabilistic rhythm until only one player has any coins in their possession, and is thus the winner of Left Center Right.
This game, published by George & Co., is not a skills-based game. It is, in fact, completely devoid of agency. You do not choose what player you pass coins to, you do not choose when or how many coins you put in the center pot, and there is no sideline betting to ante or change the stakes of particular coins. In other words: Left Center Right’s absolute lack of free will makes it a perfect case for mathematical modeling.
Now let’s use Python to look at “game feel” and decay from a mathematical standpoint.
Possibilities Of Play
In Left Center Right, there are 216 possible dice throws. Three six-sided dice. Six times six times six. Two-hundred-and-sixteen.
The dice are identical and they bear the markings [“L”, “R”, “C”, “O”, “O”, “O”] (I am using an “O” to stand in for a face bearing a single pip). We will define our first variable as this list of faces:
LCR_die = [“L”, “C”, “R”, “O”, “O”, “O”]
We can then create a list of all possible throws, where each item is a three-item list itself:
three_dice = []for i in LCR_die:
for n in LCR_die:
for x in LCR_die:
three_dice.append([i, n, x])
Going Broke And Hitting The Lotto
With our master list assembled (visible at the end of this notebook), we can sort for particular types of throws. For example, we can use a list comprehension to look only for the throws where we keep all our coins:
keep_all = [x for x in three_dice if x == [‘O’, ‘O’, ‘O’]]len(keep_all)27
Or where we lose them all, provided we only have three at the moment:
lose_all = [x for x in three_dice if ‘O’ not in x]len(lose_all)27
Interestingly, these two outcomes are equally likely — they both have a 1/8 (27/216 or 12.5%) chance of occurring. From a design standpoint (and forgive my lack of jargon), the pain-pleasure tradeoff is equal. When designing games we have to consider how likely the player is to feel a certain way based on game mechanics, and here it’s at an exciting 50/50 balance.
How Long Will It Last?
If you recall, there’s the option of coins entering a central pot, per se. When coins enter this middle pile, they are removed from pile, and not interacted with until the winning player claims them all upon their victory. (This part only matters if you use real money.)
The fact that coins entering the central pot can never leave means the game has a natural decay to it. As play progresses, more and more coins enter the pot until it is just a few coins in the players’ hands being passed back and forth. One (un)lucky dice roll can shift those precious few to just one player.
We can use a few more list comprehensions to analyze this state of decay. First we look at how likely you are to not put a coin in the pot on any given throw:
none_to_pot = [x for x in three_dice if ‘C’ not in x]len(none_to_pot)125
More than half the time you roll, you won’t put a coin in the pot! That must promote a general feeling of safety, but what of the times you do put a coin (or more) in the pot?
some_to_pot = [x for x in three_dice if ‘C’ in x]len(some_to_pot)91
The inverse of this, which really just 216–125, is significantly smaller, such that the relationship between them is 1.37:1 (they’re coprime so no clean ratios today folks). This produces a lessened feeling of loss-to-the-pot, and encourages the sensation that 1) I can win because I’m not losing to the pot and 2) the game isn’t winding down too quickly for the tension to be lost.
The Coin Pile At The End Of The Rainbow
Overall, LCR implements a series of mathematical relationships that ensure that play is non-punishing enough for it to be a casual dice game. It also ensures that, while decay is inevitable and fundamental, it doesn’t occur quick enough that play feels meaningless.
I’m working on a bigger repo of this over here on GitHub, and will be doing a part-two blog post on this. The next goal is to run a simulationist approach and look at how quickly games decay with different numbers of dice and players. Reach out on Twitter @zych_steven for feedback or just to say hello!