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

• 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.

-

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.

-

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. – TwiNight Jan 10 '13 at 22:03
@TwiNight: fixed it – marinus Jan 11 '13 at 18:32
Negative points when user wins. You can fix by `|Z-21×X` which doesn't change char count – TwiNight Jan 11 '13 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. – Brian Diggs Apr 7 '14 at 17:28

Mathematica 208172166 159

``````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. – DavidC Jan 10 '13 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. – Dr. belisarius Jan 10 '13 at 2:25
It now seems to be working fine. – DavidC Jan 10 '13 at 3:28
@dude Much better now – Dr. belisarius Jan 10 '13 at 20:16
Really nice. +1 – Mr.Wizard Jan 13 '13 at 6:54

Ruby 1.8, 165

``````i,s,*d=getc,21,[4]*5<<1,[3]*5<<6,[2,5]*3
puts"#{s.times{p r=[i,i-1].map{|o|d[o%3][rand 6]};s+=r[0]<=>r[1]}>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[1]
g[2]
g[3]
``````

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. – ugoren Jan 9 '13 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`. – ugoren Jan 9 '13 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. – ugoren Jan 9 '13 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")
``````
-