# Non-transitive dice game

Those of you who like Numberphile would be familiar with Dr. James Grime, who described a non-transitive dice game on his channel.

The game consists of three 6-faced dice:

• Die 1: 3,3,3,3,3,6
• Die 2: 2,2,2,5,5,5
• Die 3: 1,4,4,4,4,4

Two players each select a die to use. They roll them and the higher die wins, best-of-whatever.

Probabilistically, die 1 beats dies 2 with >50% chance. Similarly, die 2 beats die 3, and, interestingly, die 3 beats die 1.

Write a program taking 1, 2 or 3 as input. This indicates the die the user chooses. The program then choose the die that would beat the user and output the results of 21 rolls, and "Computer/User wins with x points"

# Rules

• Code-golf, votes as tiebreaker
• You must use RNG (or the likes) to actually simulate the dice rolls.
• I am not too strict on output format. It's okay as long as you show the dices, somehow separate between the 21 rolls (in a way different from how you separate the dice in the same roll), and output that sentence above.
• Input can be stdin, command line argument, from screen, etc.

# Example

Input

1


Output

4 3
4 3
4 3
4 3
4 3
4 3
4 3
4 3
4 3
4 6
1 3
4 3
4 3
1 3
4 3
1 3
4 3
4 3
4 3
4 3
4 6
Computer wins with 16 points


Here, the user chooses die 1 and his rolls are shown on the right column. The program chooses die 3 and beats him.

## APL (106 114)

'Computer' 'User'[1+X],'wins with','points',⍨|Z-21×X←11>Z←+/>/⎕←⍉↑{⍵[{?6}¨⍳21]}¨(↓5 6⍴545170074510753⊤⍨18⍴7)[⎕+⍳2]


Explanation:

• (↓5 6⍴545170074510753⊤⍨18⍴7)[⎕+⍳2]: The big number is a base-7 representation of the dice. We make a 6x5 matrix containing the values of the dice in the order: 2 3 1 2 3. Ask for user input and add this to the vector 1 2, and select these lines from the matrix. Because the list of dice is shifted, the user now gets the one he selected (on the right) and the computer gets the stronger one.
• {⍵[{?6}¨⍳21]}¨: do 21 rolls for each of these two dice.
• ⎕←⍉↑: put the rolls in matrix form and output them.
• Z←+/>/: get the score of the computer (amount of times the computer's value was higher than the user's)
• X←11>Z: set X to whether the user won (if 11 is higher than the computer's score).
• 'Computer' 'User'[1+X]. X is whether the user won.
• 'wins with','points',⍨|Z-21×X: Z is the computer's score, so if the computer won display Z, otherwise display 21-Z.
• The score is not the difference of the totals (which is expected to be 0 for all pairs of dice), instead, the winner of each of the 21 rolls get 1 point. In the example, the user has 5 points (from winning 5 rolls: 4-6, 1-3, 1-3, 1-3, 4-6) and the computer get the 16 points rest. Jan 10, 2013 at 22:03
• @TwiNight: fixed it Jan 11, 2013 at 18:32
• Negative points when user wins. You can fix by |Z-21×X which doesn't change char count Jan 11, 2013 at 21:42

# R - 228

d=matrix(rep(c(rep(3,5),6,2,2,2,5,5,5,1,rep(4,5)),2),6)
x=scan()
r=expand.grid(Computer=d[,x+2],User=d[,x])[sample(36,21,T),]
print(r)
s=summary.factor(names(r)[max.col(r)])
cat(names(which.max(s)),"wins with",max(s),"points\n")


Example run:

> source('ntd.R')
1: 2
2:
Computer User
28          3    5
31          3    5
36          6    5
18          6    2
11          3    2
31.1        3    5
14          3    2
8           3    2
9           3    2
17          3    2
2           3    2
29          3    5
3           3    2
16          3    2
4           3    2
21          3    5
14.1        3    2
23          3    5
16.1        3    2
17.1        3    2
19          3    5
Computer wins with 14 points

• You can replace summary.factor with table, saving 9 characters. Apr 7, 2014 at 17:28

## Mathematica 208172166 159

Spaces added for clarity

b=Boole;{#, Row@{
If[# > 10, "Play", "Comput"], "er wins with ",
Max[#, 21 - #], " points"} &@ Total[b[#1 > #2] & @@@ #]} &@
Table[1 + i + 3 b[6 Random[] > 2 i + 1],{21}, {i, {#, Mod[# + 1, 3]}}] &

• I think the output is supposed to list the values of each roll of the dice. Jan 10, 2013 at 1:45
• @dude yep, I lost it while testing. I made a quick fixup just to keep the ball running. I'll think later how to improve it. Jan 10, 2013 at 2:25
• It now seems to be working fine. Jan 10, 2013 at 3:28
• @dude Much better now Jan 10, 2013 at 20:16
• Really nice. +1 Jan 13, 2013 at 6:54

### GolfScript, 112 105 characters

3,21*{..+6rand<3*+)}%3/\{)\.+-1%>2<.p~<}+,,"User
Computer"n/1$11<=" wins with "+\[.~22+]$1>~+" points"+


Run it online.

The script expects the input on STDIN and then prints the outcome of the dice rolls (first column computer, second user) and the final statistics to STDOUT.

## Ruby 1.8, 165

i,s,*d=getc,21,*5<<1,*5<<6,[2,5]*3
puts"#{s.times{p r=[i,i-1].map{|o|d[o%3][rand 6]};s+=r<=>r}>s?"Human":"Computer"} wins with #{[s/=2,21-s].max} points"


getc gets the ascii value of the input (ruby 1.8 only), which happily is congruent modulo 3 to its integer value.

s starts out at 21, so s.times{code} will execute code 21 times and return 21. On each iteration, the loop either adds or subtracts 1 from s depending on who wins, so we can see who won by seeing whether s has ended up below 21. Neat so far, but then I need the clumsy expression [s/=2,21-s].max to extract the actual number of points. I've long wanted to do arithmetic with the return value of <=>, so I'm happy anyway.

## Mathematica 234 247

Code

g@n_ := {t = RandomChoice[{{5, 25, 1, 5}/36 -> {{3, 1}, {3, 4}, {6, 1}, {6, 4}},
{5, 1, 5, 1}/12 -> {{2, 3}, {2, 6}, {5, 3}, {5, 6}},
{1, 1, 5, 5}/12 -> {{1, 2}, {1, 5}, {4, 2}, {4, 5}}}[[n]], 21],
Row[{If[(c = Count[t, {x_, y_} /; y > x]) > 10, "Computer ", "Player "],
"wins with ", If[c > 10, c, 21 - c], " points"}]}


Usage

{Player's roll, Computer's roll}

g
g
g Explanation

n is the number 1, 2, or 3 that corresponds to the die of the player. Because n also determines (but does not equal) the die of the computer, we can generate all possible rolls of the dice when n=1, n=2, n=3. We can also determine their respective probabilities.

Examine the data right after RandomChoice:

{5, 25, 1, 5}/36 -> {{3, 1}, {3, 4}, {6, 1}, {6, 4}}

If the player draws die 1, the only possible outcomes are the following 4 pairs

{{3, 1}, {3, 4}, {6, 1}, {6, 4}}

The respective probabilities of these pairs are

{5, 25, 1, 5}/36, that is,

{5/36, 25/36, 1/36, 5/36}

RandomChoice[<data>, 21] outputs 21 rolls of the two dice.

## C, 205 191

p;r(c){return 1+c+3*(rand()%6>2*c);}main(i,c,q,s){for(c=51-getchar();++i<23;printf("%u %u\n",q,s))q=r(c),p+=(s=r(-~c%3))<q;printf("%ser wins with %u points",p<11?"Comput":"Us",p<11?21-p:p);}


Reads the user's choice from stdin.

• Some tips: for(c=51-getchar(p=0);, printf("%ser wins), reorder expression in r to start with ( and save space. Jan 9, 2013 at 7:50
• And more: (c+1)%3 -> -~c%3, make p static (initialized to 0), remove {} after for (;->, within them), use p<11?: twice within printf instead of assigning p,q. Jan 9, 2013 at 8:37
• And you can set s,q in the loop printf, and increment p afterwards, thus saving parentheses. Also change the c assignment to use %3 or %7, giving a different order of 0,1,2. Jan 9, 2013 at 15:36

# Factor

## Without: 300

USING: arrays formatting io kernel math math.parser prettyprint random sequences ;
IN: N
CONSTANT: d { { 3 3 3 3 3 6 } { 2 2 2 5 5 5 } { 1 4 4 4 4 4 } }
: p ( -- ) 1 read string>number [ 3 mod 1 + ] keep [ 1 - d nth ] bi@ 2array 21 iota [ drop first2 [ random ] bi@ [ 2array . ] 2keep < ] with map [ ] count [ 11 > "Comput" "Play" ? ] [ "er wins with %d points" sprintf ] bi append print ;


Yeah, Factor's not really the language to use when golfing, but it's nice.

# Python 182

from random import*
u=2+input()
r=[eval("int(choice(0x1d67e987c0e17c9[i%3::3])),"*21)for i in(u,u-1)]
U,C=map(sum,r)
print r,['Us','Comput'][U<C]+'er wins with %d points'%abs(U-C)


## R 206

u=scan()
D=list(c(rep(3,5),6),c(2,5),c(1,rep(4,5)))
S=sample
U=S(D[[u]],21,T)
C=S(D[[(u+1)%%3+1]],21,T)
print(cbind(U,C))
W=sum(U>C)
I=(W>10)+1
cat(c("Computer","User")[I],"wins with",c(21-W,W)[I],"points")