# Left Center Right (LCR) code golf

At a party, I was introduced to the game LCR. Now it's not a great game as there's no skill but only random chance. But it got me thinking, I could code this, and I made a quick program in R to model the game.

Rules of the game modified from Wikipedia to match how we played:

Each player receives at least 3 chips. Players take it in turn to roll three six-sided dice, each of which is marked with "L", "C", "R" on one side, and a single dot on the three remaining sides. For each "L" or "R" thrown, the player must pass one chip to the player to their left or right, respectively. A "C" indicates a chip to the center (pot). A dot has no effect.

If a player has fewer than three chips left, they are still in the game but their number of chips is the number of dice they roll on their turn, rather than rolling all three. When a player has zero chips, they pass the dice on their turn, but may receive chips from others and take their next turn accordingly. The winner is the last player to put chips into the center.

Contest: write a program in your language of choice that takes input for the number of players and the number of starting chips and simulates a game of LCR, showing the state of the game after each player has rolled.

For example, a game might be output as:

[[[3,3,3,3],0],[[1,4,3,4],0],[[1,4,3,4],0],[[1,4,1,4],2],[[1,4,1,2],4],
[[0,4,1,3],4],[[0,3,2,3],4],[[0,3,0,3],6],[[0,3,1,1],7],[[0,3,1,1],7],
[[2,0,1,1],8],[[2,0,0,1],9],[[2,0,0,0],10],[[0,1,0,0],11],
[[1,0,0,0],11],[[1,0,0,0],11],[[1,0,0,0],11],[[0,0,0,0],12]]


ht: JonathanAllan

The output doesn't have to look exactly like this, but it should be easy to discern the dice roll, how many chips each player has, and how many chips the centre has for each turn.

It's code golf so the shortest code wins.

• "it should be easy to discern the dice roll" - it's implicit (hence easy to discern) from the chip states, as is the player who rolled, since it's turn based. I'd argue that this example output has everything necessary: [[[3,3,3,3],0],[[1,4,3,4],0],[[1,4,3,4],0],[[1,4,1,4],2],[[1,4,1,2],4],[[0,4,1,3],4],[[0,3,2,3],4],[[0,3,0,3],6],[[0,3,1,1],7],[[0,3,1,1],7],[[2,0,1,1],8],[[2,0,0,1],9],[[2,0,0,0],10],[[0,1,0,0],11],[[1,0,0,0],11],[[1,0,0,0],11],[[1,0,0,0],11],[[0,0,0,0],12]] - is that the case? Feb 19, 2019 at 3:44
• @JonathanAllan, that works for me. Feb 19, 2019 at 3:49
• @KevinCruijssen, good question, I guess I'll allow either way. Feb 20, 2019 at 15:16
• @CTHall In that case I've edited both my answers (Java and 05AB1E) and included both with and without. :) Feb 20, 2019 at 17:52
• I almost want to do this on Runic where each instruction pointer acts as a given player. Not sure I can (even ignoring number of players input), but it'd be neat if I could. Feb 20, 2019 at 19:03

# Emacs Lisp, 279 bytes

(defmacro n(i)(incf(nth ,i c)))
(defun f(p s)(g(let((a'(0)))(dotimes(i p)(push s a))(princ a))0 p))
(defun g(c v p)(dotimes(i(min(nth v c)3))(decf(nth v c))(case(random 6)(0(n(mod(1- v)p)))(1(n(mod(1+ v)p)))(2(n p))(t(n v))))(princ c)(or(eq(-sum c)(nth p c))(g c(mod(1+ v)p)p)))


Use this function as (f 4 3).

(defmacro n (i) (incf (nth ,i c)))

(defun f(p s)
(g
(let ((a '(0)))
(dotimes (i p)
(push s a))
(princ a))
0
p))

(defun g (c v p)
(dotimes (i (min (nth v c) 3))
(decf (nth v c))
(case (random 6)
(0 (n (mod (1- v) p)))
(1 (n (mod (1+ v) p)))
(2 (n p))
(t (n v))))
(princ c)
(or (eq (-sum c) (nth p c))
(g c (mod (1+ v) p) p)))


Output example:

(3 3 3 3 0)(1 4 3 4 0)(2 2 4 4 0)(2 2 2 5 1)(4 2 2 3 1)(2 2 2 4 2)(2 1 3 4 2)(2 2 0 4 4)(2 2 0 4 4)(1 2 0 4 5)(2 1 0 4 5)(2 1 0 4 5)(2 1 1 3 5)(0 1 1 3 7)(1 0 1 3 7)(1 0 1 3 7)(1 0 3 1 7)(1 0 3 1 7)(1 0 3 1 7)(1 1 2 1 7)(1 1 3 0 7)(0 1 3 0 8)(1 0 3 0 8)(1 1 1 1 8)(1 1 2 0 8)(0 1 2 1 8)(0 1 2 1 8)(0 1 1 1 9)(0 1 1 1 9)(0 1 1 1 9)(0 1 1 1 9)(0 1 1 1 9)(0 1 1 0 10)(0 1 1 0 10)(0 0 1 0 11)(0 0 1 0 11)(0 0 1 0 11)(0 0 1 0 11)(0 0 1 0 11)(0 0 0 0 12)


# Java 8, 281277275274 253 bytes

Version which outputs the same state when a turn player has 0 chips left:

p->n->{java.util.Arrays A=null;int c[]=new int[p],i=0,t,r,s=1,u,f=9;for(A.fill(c,n);s>0;f=0,System.out.print(A.toString(c)))for(t=c[++i%p],t=t>3?3:t;t-->f;r*=Math.random(),c[i%p]-=1-r/3,s=c[u=(i+r-1+p)%p]+=1-r&1-r/4,c[u]=s<0?0:s,s=A.stream(c).sum())r=6;}


Starts with the third player in the array.

Try it online.

Version which skips players with 0 chips left (274 bytes):

p->n->{java.util.Arrays A=null;int c[]=new int[p],i=p,t,r,s=1,u,f=9;for(A.fill(c,n);s>0;f=0,System.out.print(A.toString(c))){for(t=c[i%p],t=t>3?3:t;t-->f;r*=Math.random(),c[i%p]-=1-r/3,s=c[u=(i+r-1+p)%p]+=1-r&1-r/4,c[u]=s<0?0:s)r=6;for(s=A.stream(c).sum();s>0&c[++i%p]<1;);}}


Starts at the first player in the array.

Try it online.

-7 bytes thanks to @OlivierGrégoire.

Explanation (of the second version):

p->n->{                      // Method with two integer parameters and no return-type
java.util.Arrays A=null;   //  Create a static Arrays-object to save bytes
int c[]=new int[p],        //  Integer-array with chips of each player (0 by default)
i=p,                   //  Index integer, starting at the amount of players
t,                     //  Temp integer to roll 3 dice
r,                     //  Temp integer for the dice-result
s=1,u,                 //  Temp integers (and s is also the total-sum integer)
f=9;                   //  Flag integer, starting at a single digit above 3
for(A.fill(c,n);           //  Give each player in the array the chips
s>0                    //  Loop as long as the total-sum is not 0 yet
;                      //    After every iteration:
f=0,                  //     Set the flag to 0
System.out.print(A.toString(c))){
//     Print the current state
for(t=c[i%p],            //   Set t to the current player's chips
t=t>3?3:t;           //   If this is larger than 3: set it to 3 instead
t-->f                //   Loop that many times (1, 2, or 3)
//   (the flag is used to skip this loop the first iteration,
//   so we can print the initial state)
;                    //     After every iteration:
r*=Math.random(),   //      Roll the dice in the range [0,5]
c[i%p]-=r<3?        //      If the dice-roll is 0, 1 or 2:
1          //       Remove a chip from this player
:0,         //      Else: Leave the chip-amount the same
s=c[u=(i+r-1+p)%p]  //      If the dice-roll is 0, go to the player left
//      If the dice-roll is 2, go to the player right
+=1-r&1-r/4,    //       And add a chip to this player
c[u]=s<0?0:s)       //      Change negative amount of chips to 0
r=6;                   //    Reset the dice-roll to 6 so we can roll again
for(s=A.stream(c).sum(); //   Calculate the total sum of the chips of the players
s>0&                 //   If this sum is larger than 0:
c[++i%p]<1;);}}     //    Determine the next player in line with at least 1 chip

• Could leave my upvote without a (tiny) golf :D s=0;for(int C:c)s+=C; (21 bytes) can be replaced by s=A.stream(c).sum(); (20 bytes) Feb 20, 2019 at 11:06
• Also, not sure if entirely ok: c[i%p]-=r<3?1:0c[i%p]-=1-r/3. This would save 2 bytes. Feb 20, 2019 at 11:11
• @OlivierGrégoire Ah, smart way of re-using the A from java.util.Arrays. :D And by putting it in the loop to save on the semi-colon it's -2 bytes. And 1-r/3 is indeed correct (see here). Thanks. Feb 20, 2019 at 12:03
• Nice trick with the loop comparison decrementing. I might steal that. Feb 20, 2019 at 12:14
• Ignore my previous deleted comment: my truth table was off. This is the fixed one: s=c[u=(i+r-1+p)%p]+=1-r&1-r/4 (saves 2 bytes, compared to s=c[u=(i+r%2*2-1+p)%p]+=r<2?1:0) Feb 20, 2019 at 12:47

# Python 2, 159 148 bytes

from random import*
n,c=input()
g=[c]*n;i=0
while sum(g):exec"r=randrange(6);g[i]-=1;g[i-[0,1,~-n][max(0,r-3)]]+=r>0;"*min(3,g[i]);i=(i+1)%n;print g


Try it online!

Prints all players chips after every roll

• Good attempt, but the code doesn't show the amount of chips in the centre. Feb 19, 2019 at 15:41
• @CTHall The chips in the center is always equal to n*c - sum(players). If I need to explicitly write it out, I will Feb 19, 2019 at 16:01
• that's true. I'll allow it. Feb 20, 2019 at 15:09

# Jelly, 39 bytes

+2 to fix repetition behaviour (¡ must be preceded by a nilad so «3Ḣ$ -> ⁸FḢ«3) If we can define the output lists to be rotated to have the chips belonging to the player who acted previously at the left we can do away with the right-most 6 bytes for 33 bytes (however, in my opinion, it is somewhat awkward to read that). ẋµ’1¦‘.,2ŻX¤¦$¹Ø.X¤?⁸FḢ«3¤¡ṙ1µSÐ¿ṙ"JC A dyadic Link accepting chips-per-player on the left and number-of-players on the right which yields a list of players chip counts as at the start of the game and after each turn (including turns where 0 chips forces a pass). Try it online! ### How? Each player in turn, up to three times, depending on their chip count, flips a coin. When a player flips heads they do nothing but if they flip tails they then roll a three sided die losing a chip to L, C or R. (Note that 0 flips when a player has 0 chips is equivalent to passing.) This is repeated until the sum of the players chips is 0. The implementation rotates the players left by one place each turn and then rotates the resulting states back to all be aligned as if they were not. ẋµ’1¦‘.,2ŻX¤¦¹Ø.X¤?⁸«3Ḣ¤¡ṙ1µSÐ¿ṙ"JC - Link: chipsPerPlayer, C; numberOfPlayers, P
ẋ                                      - repeat C P times (making a list of P Cs)
Ð¿       - collect up results in a list while...
S         - ...Ð¿ condition: sum (while players have chips)
µ                          µ          - ...Ð¿ do: the monadic chain:
¡             -   repeat...
⁸                  -     chain's left argument (the chip list)
«3                -     minimum with three (vectorises)
Ḣ               -     head -- i.e. min(left-most player's chips, 3)
?                   -   ...¡ action: if...
Ø.                      -       the list [0,1]
X                     -       random choice (0 is falsey while 1 is truthy)
$- ...? then: last two links as a monad: ¦ - sparsely apply... 1 - ...¦ to indices: one (the left-most) ’ - ...¦ action: decrement (player lost a chip) ¦ - sparsely apply... ¤ - ...¦ to indices: nilad and link(s) as a nilad: .,2 - literal pair of literals .5 and two = [.5,2] Ż - prepend a zero = [0,0.5,2] X - random choice - -- Note application to index .5 is a no-op - index 0 is the right-most entry (L) - index 2 is the second entry (R) ṙ1 - rotate the list left by one for the next Ð¿ loop$ - last two links as a monad:
J    -     range of length -- i.e. [1,2,3,...,turns+1]
C   -     complement = 1-x        [0,-1,-2,...,-turns]
"     -   zipped-appliction of:
ṙ      -     rotate left by
-   -- i.e. rotate 1st left by 0, 2nd left by -1, ...)

• I'm a bit impressed as to how people code in these languages that look like line noise. :) But then I only know a couple of languages kinda, so maybe with more experience it'll come. Feb 20, 2019 at 18:21
• You could check out the tutorial at the wiki, it's pretty good. Once I post the code breakdown you will hopefully follow what I've done... Feb 20, 2019 at 18:23
• ...this is subtly incorrect behavior, though? Per spec, you need to roll all three dice, not just one coin flip. Unless the description is in error and the code is fine. Feb 21, 2019 at 12:58
• @Stackstuck - the description overview is slightly misleading, the coin is flipped each time; I shall fix it - thanks. FWIW the code breakdown description is right - the coin flip branching, Ø.X¤?, is nested inside the repeat-up-to-3-times instruction, ⁸«3Ḣ¤¡. Feb 21, 2019 at 15:01
• Ah, okay. Glad I could help. Feb 22, 2019 at 1:03

# C#, 356?+13? Bytes

Requires using System; for a total of +13 bytes to the code shown below, if I'm required to count that. Otherwise just plonk it in any class and call L(players, starting chips);.

static int i,j,k,l;public static void L(int p,int s){var r=new Random();var x=new int[p];for(i=0;i<p;i++)x[i]=s;
for(i=0;i<s*p;){for(j=0;j<p;j++){for(l=0;l<x[j]&l<3;l++){k=r.Next(-1,5);if(k<2){if(k==0){x[j]--;i++;}else{x[(p+j+k)%p]++;x[j]--;}}}Console.Write(a(x)+i);}}}public static string a(int[] x){var n="|";for(l=0;l<x.Length;)n+=x[l++]+" ";
return n;}


Sample output for a 2,2 game:

|1 3 0|2 2 0|1 3 0|1 3 0|0 4 0|0 3 1|0 3 1|2 1 1|1 2 1|1 2 1|0 3 1|0 3 1|0 3 1|1 1 2|1 1 2|1 1 2|0 2 2|1 1 2|0 1 3|1 0 3|0 1 3|0 1 3|0 1 3|1 0 3|1 0 3|1 0 3|0 1 3|1 0 3|0 1 3|0 0 4


Less golfed version:

using System;
//class omitted.
static int i,j,k,l;
public static void LCR(int pl, int sc){
var r=new Random();
var state = new int[pl];
for(i=0;i<pl;i++)state[i]=sc;
for(i=0;i<sc*pl;){
for(j=0;j<pl;j++){
for(l=0;l<state[j] && l<3;l++){
k=r.Next(-1,5);
if(k<2){
if(k==0){state[j]--;i++;}else{state[(pl+j+k)%pl]++;state[j]--;}
}
}
Console.Write(a(state)+i);
}
}
}
public static string a(int[] x){
var n="|";
for(l=0;l<x.Length;)n+=x[l++]+" ";
return n;
}

• Well, this is my first answer here ever. Please don't eat me. Feb 20, 2019 at 6:53
• Ah, drat. I got my array printing behavior confused with Java. I'll just be...right back with a revision. Feb 20, 2019 at 7:10
• Okay, that's fixed, output should definitely work. Feb 20, 2019 at 7:22
• ...oh, nope, there's one more error. Feb 20, 2019 at 7:29
• People saying modulo when the behavior is actually remainder should...not do that. There, I'm 90% sure this works now. Feb 20, 2019 at 7:37

# C# (Visual C# Interactive Compiler), 201 199 bytes

n=>m=>{var r=new Random();var j=Enumerable.Repeat(n,m).ToList();for(int i=0;j.Any(c=>c>0);i++,Print(j))for(int k=0,x=r.Next(6);k++<Math.Min(j[i%m],3);j[((x<1?-1:1)+i+m)%m]+=x<2?1:0,j[i%m]-=x<3?1:0);}


Try it online!

startingChips=>playerNum=>{
//Instantiate a new random number generator
var rng = new Random();
//Create a list of chips
var players = Enumerable.Repeat(startingChips, playerNum ).ToList();
//Loop as long any player still has chips
for(int turnNum = 0;players.Any(c=>c>0);
//And print the result every iteration
i++,Print(j))
//Get a random number within the range of 0-5 and loop for...
for(int k = 0,randomNum = rng.Next(6);
//either 3 or the amount of chips we have, whichever is smaller
k++<Math.Min(players[turnNum % playerNum ],3);
//Increment either the right player if the random number is 1, else increment the right player if it is 0
players[((randomNum<1?-1:1)+ turnNum + playerNum ) % playerNum ]+=x<2?1:0,
//Decrement current player if the die roll is under 3
players[ turnNum % playerNum ]-=x<3?1:0);}


# Charcoal, 61 bytes

≔⁰ηＷΣθ«≔Ｅθ⭆⌊⟦κ×³⁼λη⟧‽⁶ιＵＭθ⁻⁺⁺κ№§ι⊕λ3№§ι⊖λ5ＬΦ§ιλ›μ2≔﹪⊕ηＬθη⟦⪫θ,


Try it online! Link is to verbose version of code. Alternates between outputting the dice rolls and chips left (neither the initial number of chips nor the number of chips in the centre are included in the output). Explanation:

≔⁰η


ＷΣθ«


Repeat until nobody has any chips left.

≔Ｅθ⭆⌊⟦κ×³⁼λη⟧‽⁶ι


Roll up to three dice for the current player. These dice are labelled 0-5, where 0-2 represent the dot, 3 is pass to left, 4 is to centre, 5 is to right.

ＵＭθ⁻⁺⁺κ№§ι⊕λ3№§ι⊖λ5ＬΦ§ιλ›μ2


Add the number of chips the player on the right passed left and the number of chips the player on the left passed right, but subtract the number of chips the player themselves passed on.

≔﹪⊕ηＬθη


⟦⪫θ,


Output the the new numbers of chips held by the players.

It's actually simpler for everyone to roll their dice simultaneously, which can be done in 50 bytes, including printing the dice rolls as well as the chips left:

ＷΣθ«≔Ｅθ⭆⌊⟦κ³⟧‽⁶ιＵＭθ⁻⁺⁺κ№§ι⊕λ3№§ι⊖λ5ＬΦ§ιλ›μ2⟦⪫ι,⪫θ,


Try it online! Link is to verbose version of code.

• I'm not sure, but it doesn't seem as if it accounts for the number of chips held after each role, not each round. Feb 26, 2019 at 19:36
• @CTHall Oh, you mean each player rolls individually, and then the numbers of chips are updated? Sorry, I overlooked that. I'll update my answer as soon as I have the time.
– Neil
Feb 27, 2019 at 1:08

# 05AB1E, 58504952 49 bytes

Version which outputs the same state when a turn player has 0 chips left (50 49 52 49 bytes):

и[=ÐO_#¾è3‚Ws\F5ÝΩ©3‹iε¾¹%NQ-}®≠iε®<¾+¹%NQ+}}}}D0›*¼


Try it online.

Version which skips players with 0 chips left (58 57 60 57 bytes):

и[=DO_#[D¾èDĀ#\¼}3‚Ws\F5ÝΩ©3‹iε¾¹%NQ-}®≠iε®<¾+¹%NQ+}}}}D0›*¼


Try it online.

The first input is the amount of players, second input the amount of chips per player.

Explanation (of the second version):

и                    # Create a list with a size of the (first) implicit input,
# filled with the second (implicit) input
[                    # Start an infinite loop:
=                   #  Print the list with trailing newline, without popping the list
DO_#                #  If the total amount of chips is 0: stop the infinite loop
[                   #  Start an inner infinite loop:
D¾è                #   Get the chips of the I'th player (I is 0 by default)
D               #   Duplicate this
Ā#             #   If it is NOT 0: stop the inner infinite loop
\            #   Remove the duplicated chips for the next iteration
¼           #   And increase I by 1
}                   #  After the inner infinite loop:
3‚ß                 #  If the amount of chips is larger than 3: use 3 instead
F                #  Loop that many times:
5ÝΩ             #   Roll a random dice in the range [0,5]
©3‹i            #   If the dice-roll is 0, 1, or 2:
ε¾¹%NQ-}    #    Remove a chip from the I'th player
®≠i         #    If the dice-roll is NOT 1:
ε®<¾+    #     Go to the player left if 0; or right if 2
¹%NQ+}   #     And increase that player's chips by 1
}}}              #  Close both if-statements and the loop
Dd*           #  Make any negative amount of chips 0
¼          #  Increase I by 1

• I'm not sure it is working correctly. It seems players can gain chips on their turn which shouldn't happen. Mar 8, 2019 at 3:53
• @CTHall Are you sure? In which of the four TIO versions did you see this? I only checked the last (legacy version which skips players with 0 chips), but the only time it increases a player is when another player is at turn. Here is that last one with added debug-line so you can see which (0-indexed) player is at turn. Mar 8, 2019 at 7:39
• The legacy ones seem to be correct, but the nonlegacy seems to have the error I mentioned. Mar 8, 2019 at 14:41
• @CTHall Ah, you're indeed right. I see a line [2, 3, 3, 3] followed by [2, 2, 2, 6].. :S I'll see if I can find the cause and fix it. If not, I can always delete it and only use the legacy, since it outputs a lot more anyway.. The new version is pretty slow with complex loops for some reason.. >.> Mar 8, 2019 at 16:55
• @CTHall I've been able to pinpoint the issue, but unable to fix it. For some reason the order of the list get changed right after increasing the global counter_variable.. I tried to reproduce the issue in a simpler example, but am unable to. It has something to do with the nested if-statements and maps inside the infinite loop, but it's definitely weird.. Anyway, I've removed that version and now only the legacy (and faster) version remains, which works as intended. Mar 8, 2019 at 18:36