Rolling three dice and show the probabilities

4

Roll 3 dice, count the two highest two values and add them to the result. Every 1 must be rolled once again.

Now show the average throw after 1000000 tries and the probabilities for each result occurring:

Desired Result:

avg(9.095855)
2: 0.0023
3: 0.0448
4: 1.1075
5: 2.8983
6: 6.116
7: 10.1234
8: 15.4687
9: 18.9496
10: 19.3575
11: 16.0886
12: 9.8433

Sven

Posted 2012-12-14T23:35:56.270

Reputation: 141

Still unclear to me: what if I get a 1 and reroll it once again and get a 1 again? – edc65 – 2015-07-05T09:40:56.540

2Are we required to throw random dice, or may we calculate the probabilities directly? – primo – 2012-12-15T06:22:14.683

In the second sentence, do you mean "Every 1 must be rolled once again"? Yeah, I mean, I know you do, but it can be read literally as "or you can leave it if you can't be bothered" and that would result in a shorter algorithm! – Mr Lister – 2012-12-15T17:09:58.700

Random of course, and you're right, must is more fun ;) – Sven – 2012-12-15T18:25:22.940

So, that is roll 3 dice, re-roll the 1s, take away to lowest die, sum the two, and repeat 1mil times? – TwiNight – 2013-01-03T05:34:38.300

Answers

5

Mathematica 150 146 94 115 108

Edit: This version is a suggestion from @belisarius. Much shorter and faster than my own code (found in the earlier versions).

r=RandomInteger;t=Tr/@Rest/@Sort/@(5~r~{10^6,3}/. 0:>r[5]);
{Mean@t+2,{#[[1]]+2,#[[2]]/10^4}&/@Sort@Tally@t}//N

{9.09684, {{2., 0.0028}, {3., 0.0456}, {4., 1.1097}, {5., 2.8752}, {6., 6.1246}, {7., 10.122},
{8., 15.513}, {9., 18.8956}, {10., 19.3514}, {11., 16.074}, {12., 9.8861}}}

DavidC

Posted 2012-12-14T23:35:56.270

Reputation: 24 524

1In 96: r=RandomInteger;{#[[1]]+2,#[[2]]/10^4}&/@Sort@Tally[Tr/@Rest/@Sort/@(5~r~{10^6,3}/. 0:>r[5])]//N – Dr. belisarius – 2012-12-16T16:57:06.297

I get the following message with your code: RandomInteger::array: "The array dimensions {1000000,3\ ‌} given in position 2 of RandomInteger[5,{1000000,3\ ‌}] should be a list of non-negative machine-sized integers giving the dimensions for the result. " – DavidC – 2012-12-16T17:01:21.410

2r = RandomInteger; {#[[1]] + 2, #[[2]]/10^4} & /@ Sort@Tally[Tr /@ Rest /@ Sort /@ (5~r~{10^6, 3} /. 0 :> r[5])] // N – Dr. belisarius – 2012-12-16T17:03:13.210

And then remove all the spaces except the one before the 0 in /. 0 – Dr. belisarius – 2012-12-16T17:04:17.377

1Works. And about 10000 x faster than mine. Why don't you submit it as your own? – DavidC – 2012-12-16T17:08:50.817

1Feel free to include it as an upgrade to your answer. I usually don't like answering in this site because the input/output is often required in a way more fitted to other languages. – Dr. belisarius – 2012-12-16T17:23:33.733

Thanks. Yes, the formatting constraints can be a pain. BTW, I had to insert code to obtain the mean. Hence the increase in size. – DavidC – 2012-12-16T18:17:30.537

4

APL 110 103

r←11⍴0                                        
i←1                                           
l:r←r+(j←1+⍳11)=+/2↑n[⍒n←3↑((3↑x)~1),3↓x←?6⍴6]
i←i+1                                         
→(i≤k←10*6)/l                                 
((+/r×j)÷k)                                   
j,[1.1]r÷10*4

I have included the results of three runs to demonstrate the degree of repeatability over 1000000 iterations.

9.092186    9.093053    9.093897   
  2  0.0022   2  0.0019   2  0.0023
  3  0.0442   3  0.0477   3  0.0452
  4  1.1064   4  1.0755   4  1.0866
  5  2.8808   5  2.887    5  2.8771
  6  6.1472   6  6.1864   6  6.1485
  7 10.1532   7 10.1163   7 10.1575
  8 15.6376   8 15.5511   8 15.5834
  9 18.8736   9 18.918    9 18.873 
 10 19.2771  10 19.3763  10 19.3315
 11 15.9702  11 16.0225  11 16.0529
 12  9.9075  12  9.8173  12  9.8419

Graham

Posted 2012-12-14T23:35:56.270

Reputation: 3 184

Very golfable. r←r+==r+←, ((3↑x)~1)==(1~⍨3↑x), 10*6==1e6, ,[1.1]==,[⍟3] – TwiNight – 2013-01-03T17:29:03.870

@TwiNight I am afraid all bar 1e6 will not work in an early version of APL+Win. I do not have the luxury of dynamic function either. Thanks all the same. – Graham – 2013-01-03T22:01:29.407

3

Python (207 194 189)

from random import*
a=lambda:randint(13,48)/7
r=range
x=[0]*13
s=0
for i in r(10**6):b=sum(sorted([a(),a(),a()])[1:]);x[b]+=1e-4;s+=b/1e6
print'avg(%f)'%s
for i in r(2,13):print`i`+':',x[i]

Algorithm:

a is the RNG, x is the list which contains the results, s is the sum. r is for code-golfing purposes.
1. Iterate through steps 2-6 1,000,000 times:
2. Get three random numbers from `a` and put them in a list.
3. Sort the list. (list is now in ascending order)
4. Take the sum of every item but the first item in the list. Call this number b.
5. Increment the (b)th index of x by 1e-4 (1/10000).
6. Increment s by b * 1e-6 (1/1000000).
7. Print out s.
8. For each item in x (excluding the first two), output the item.

beary605

Posted 2012-12-14T23:35:56.270

Reputation: 3 904

2

APL, 67

÷1e2÷+/×/x←⍉↑n,1e4÷⍨+/(n←⊂⍳12)∘.={+/2↑x[⍒x←{⍵=1:?6⋄⍵}¨?3⍴6]}¨⍳1e6⋄x

Explanation

  • ⍳1e6 Create array from 1 to milliion,
  • ¨ and for each of those
  • {+/2↑x[⍒x←{⍵=1:?6⋄⍵}¨?3⍴6]} do a roll, re-roll 1s, and sum the high dices:

    ?3⍴6 roll 3 dice,
    ¨ and for each die
    {⍵=1:?6⋄⍵} if it is a 1, replace it by a re-roll result, else don't change it.
    x← Save the result in (local) variable x,
    x[⍒x...] sort it in descending order,
    +/2↑ take the first 2 items (high dices) and return the sum.

  • +/(n←⊂⍳12)∘.= Create array of the no. of times each sum appears,
  • 1e4÷⍨ divide by 10000,
  • ⍉↑n, insert a row to the top with numbers 1 to 12, and matrix transpose it. The result would be something like the table in the question.
  • x← Save that in (global) variable x.
  • +/×/ Calculate the average of the million rolls by multiplying the columns, summing those...
  • ÷1e2÷ and divide by 100.

The result is displayed (by default)

  • ⋄x Finally, output x

Example output

9.097008        
 1  0     
 2  0.0028
 3  0.0466
 4  1.0914
 5  2.8873
 6  6.0957
 7 10.1242
 8 15.6108
 9 18.8688
10 19.2834
11 16.0979
12  9.8911

Notes

-5 chars if allowed to represent 10% by 0.1 instead of 10
-3 chars if allowed to use probabilistic approach (like o_o's) instead of explicit re-roll
+12 chars if the "avg()" is required
+2 chars if the "1" row needs to be removed
+8 chars if the colon is required in output

TwiNight

Posted 2012-12-14T23:35:56.270

Reputation: 4 187

1

TI-BASIC, not an entry

This does not meet the spec, because it doesn't show the result distribution or directly roll integers between 1 and 6, but I found a slightly clever algorithm for computing the average in one line. To get the largest two dice rolls, we pad a number larger than any of the dice rolls onto the list of three rolls, and take the median, which will be the average of the middle two numbers (two highest dice rolls). Then we just multiply by 2 to get the sum.

2ᴇ~6Σ(median(int(augment(15+36rand(3),{99})/7)),X,1,ᴇ6

Based on the speed of SuperJedi224's answer to "Death by Shock Probe", it will take over 12 hours to finish running.

lirtosiast

Posted 2012-12-14T23:35:56.270

Reputation: 20 331

1

Python, 262

import random
r=random.randint
def f():n=r(1,6);return n if n>1 else r(1,6)
l=[0.0]*13
for i in range(10**6):l[sum(sorted([f(),f(),f()])[1:])]+=1
m=zip(*[range(2,13),l[2:]])
print'avg('+`sum([a*b for a,b in m])/10**6`+')'
for e in m:print`e[0]`+': '+`e[1]/10**4`

results:

avg(9.098773)
2: 0.0021
3: 0.044
4: 1.0872
5: 2.89
6: 6.0982
7: 10.133
8: 15.5
9: 18.949
10: 19.2908
11: 16.0953
12: 9.9104

cardboard_box

Posted 2012-12-14T23:35:56.270

Reputation: 5 150

Please show your results. I'm curious. – DavidC – 2012-12-15T13:57:37.087

1

C# (599)

using System;using System.Collections.Generic;using System.Linq;namespace P{public class D{Random r=new Random(System.DateTime.Now.Millisecond);public static void Main(){var d=new D();d.G();}public int R(){return r.Next(1,7);}public int RD(){var e=new List<int>();for(var i=0;i<=2;i++){var v = R();e.Add(v != 1 ? v : R());}return e.OrderByDescending(d=>d).Take(2).Sum();}public void G(){const double l = 1000000;var t = new Dictionary<int,double>();for(var i=2;i<=12;i++)t.Add(i,0);for(var i=0;i<l;i++){var s=RD();t[s]=t[s]+1;}foreach(var a in t){Console.WriteLine(a.Key+": "+(a.Value)/10000.0);}}}}

Chris Zimmerman

Posted 2012-12-14T23:35:56.270

Reputation: 131

please read http://codegolf.stackexchange.com/faq and provide a golfed version of your answer (the least you can do is have one letter variables, inline methods where possible and avoid unnecessary whitespace). Also, provide a character count in the post title.

– Cristian Lupascu – 2012-12-15T09:23:53.683

1

Perl (177 169 168)

sub r{1+int rand 6}
for(1..1e6){@l=sort map{($q=r)>1?$q:r}(1..3);++$s{$y=$l[1]+$l[2]};$t+=$y}
print"avg(".$t/1e6.")\n";print"$_: ".$s{$_}/1e4."\n"for sort{$a<=>$b}keys%s

(NOTE: one-liner wrapped for clarity)

stacked output of three consecutive runs:

avg(9.09432)  avg(9.094793)  avg(9.092179) 
2: 0.002      2: 0.0026      2: 0.0023     
3: 0.0448     3: 0.0454      3: 0.0436     
4: 1.0872     4: 1.0904      4: 1.0944     
5: 2.8834     5: 2.8933      5: 2.8842     
6: 6.1387     6: 6.127       6: 6.1854     
7: 10.1648    7: 10.177      7: 10.1669    
8: 15.498     8: 15.5758     8: 15.508     
9: 18.9483    9: 18.8391     9: 18.9236    
10: 19.3557   10: 19.278     10: 19.3234   
11: 16.0589   11: 16.0863    11: 16.0256   
12: 9.8182    12: 9.8851     12: 9.8426    

UPDATES

  • shortening 1: eliminate $n=1e6 (insp. by Joe)
  • shortening 2: del space in keys %s

mykhal

Posted 2012-12-14T23:35:56.270

Reputation: 641

1

R - 98

S=sample
D=matrix(S(6,3e6,T),3)
D[D<2]=S(6,3e6,T)
A=colSums(D)-apply(D,2,min)
mean(A)
table(A)/1e4

Like some other answers, my output is not in the same format as the OP; I was not sure if it was a strict requirement or not:

[1] 9.095695

A
      2       3       4       5       6       7       8       9      10      11      12 
 0.0018  0.0426  1.1008  2.8748  6.1438 10.1147 15.5406 18.9276 19.3525 16.0126  9.8882 

flodel

Posted 2012-12-14T23:35:56.270

Reputation: 2 345

0

CoffeeScript, 146

r=()->~~(6*Math.random())
t=i=0;s=[];(a=[r()||r(),r()||r(),r()||r()].sort();t+=b=2+a[1]+a[2];s[b]=1e2/z+(s[b]||0))while++i<z=1e6;console.log t/z,s

Outputs the average and an object:

9.09456
[2: 0.0022, 3: 0.043400000000000216, 4: 1.103199999999895, 5: 2.9063000000017087, 6: 6.142699999999023, 7: 10.075099999989858, 8: 15.533299999977137, 9: 18.94439999996919, 10: 19.328099999968295, 11: 16.106199999975804, 12: 9.814999999990464]

rink.attendant.6

Posted 2012-12-14T23:35:56.270

Reputation: 2 776

0

JavaScript (ES6), 149

Algorithm is similar to my CoffeeScript answer; different syntax and semantics. I tried inlining the q function here which made no difference.

for(r=()=>~~(6*Math.random()),q=()=>r()||r(),t=i=0,s={};++i<(z=1e6);){a=[q(),q(),q()].sort();t+=b=2+a[1]+a[2];s[b]=1e2/z+(s[b]||0)}console.log(t/z,s)

Unminified

for (
    r = () => ~~ (6 * Math.random()), // function to generate random number between 0 - 5
      q = () => r() || r(),           // function to roll dice and if 0, re-roll once
      t = i = 0,                      // initialize counter and sum
      s = {};                         // initialize probability object
    ++i < (z = 1e5);                  // increment
) {
    a = [q(), q(), q()].sort();       // roll three dice and perform lexicographical sort
    t += b = 2 + a[1] + a[2];         // take two highest and add 2 since numbers are 0 - 5
    s[b] = 1e2 / z + (s[b] || 0)      // put into probability object as a percent
}
console.log(t / z, s)                 // STDOUT

rink.attendant.6

Posted 2012-12-14T23:35:56.270

Reputation: 2 776

0

LUA (307)

function r()
  m=math.random(1,6)
  if(m==1)then return math.random(1,6)end
  return m
end
e={}
s=0
o=1000000
for i=2,12 do e[i]=0 end
for t=1,o do
  d={}
  for i=1,3 do d[i]=r() end
  table.sort(d)
  x=d[2]+d[3]
  e[x]=e[x]+1
  s=s+x
end
print("avg("..s/o..")")
for i=2,12 do print(i..": "..e[i]/o*100) end

My first one ;)

Sven

Posted 2012-12-14T23:35:56.270

Reputation: 141

You may be able to shave off some bytes by using 10^6 and by assigning random(1,6) to a function with a shorter name, such as f. – DavidC – 2012-12-15T14:02:16.087

0

Seems to be a basic problem with the calculation and results I am seeing here.

If you must reroll the dice (all 3 or just one) when you get a 1 showing up, then the lowest possible sum of die faces you could ever have would be 4. That is, any face that shows a 1 will be rerolled. Which specifically requires that the lowest possible face is a 2. You could avoid the rerolling by generating random values from 2 .. 6, but that might be missing the point.

What this means: If you are reporting values for 2 or 3 as the sum of the faces, these are 1+1 and 2+1 respectively, the specification excludes this possibility.

That is, unless the "you must reroll the dice" only applies to the first instance of a 1. In which case, you may have a 1+1, and 2+1 case (so you'd get sums of 2 and 3 as possible answers).

Joe

Posted 2012-12-14T23:35:56.270

Reputation: 9

1Do you have code which implements this algorithm? CG&PP is less about explaining the algorithm, and more about implementing it (in the least amount of chars possible.) – beary605 – 2012-12-16T23:06:34.760

I understand this ... but the issue is that the results posted don't seem to match the specs. If you are reporting values for sum of faces = 1, 2, or 3 in your probability calcs, you have an implementation issue that needs to be resolved. That is, the algorithm as specified would never have a sum of faces less than 4. – Joe – 2012-12-16T23:40:17.707

3You only reroll once. Basically, you have a 1/36 chance of rolling a 1, and a 7/36 chance of rolling anything else. I hope that makes it a little clearer :) – beary605 – 2012-12-17T02:25:45.563

0

map{@f=(sort((&r,&r,&r)[1,2]));$d[$f[0]+$f[1]]++}(1..1E6);
map{$s+=$d[$_]*$_}(0..$#d);print"avg(".$s/1E6.")\n";map{print"$_:
".$d[$_]/1E4."\n"}(0..$#d);
sub r{$x=1+int(rand 6);$x>1?$x:&r}




    ~/play/golf/dice$ perl dice.pl 
    avg(8.000533)
    0: 0
    1: 0
    2: 0
    3: 0
    4: 3.9796
    5: 8.0376
    6: 11.9607
    7: 16.0064
    8: 20.0094
    9: 15.9636
    10: 12.0582
    11: 8.0057
    12: 3.9788

Joe

Posted 2012-12-14T23:35:56.270

Reputation: 9

0

Now a more optimized version, with a shifted RNG (no reroll), and shortened statistics calcs, also exploiting the ordering due to the ascii nature of single integers.

map{@f=(sort((&r,&r,&r)[1,2]));$i=$f[0]+$f[1];$d[$i]++;$s+=$i}(1..1E6);
print"avg(".$s/1E6.")\n";map{print"$_: ".$d[$_]/1E4."\n"}(0..$#d);
sub r{2+int(rand 5)}

As you can see, printing uses almost as much space as computing here. If you'd like a simpler output, this would save characters.

avg(8.000901)
0: 0
1: 0
2: 0
3: 0
4: 4.0007
5: 7.9769
6: 11.9652
7: 16.0226
8: 20.0156
9: 16.0389
10: 11.9983
11: 7.9861
12: 3.9957

Joe

Posted 2012-12-14T23:35:56.270

Reputation: 9

Your language? your byte count? As is, this is worth a downvote – edc65 – 2015-07-05T10:05:19.783

1hey, i'll take some inspiration from you and reshuffle some code in my solution, but i'll still use a hash for statistics (whose keys i however unfortunately have to sort with explicit comparison finally), i wonder can get it shorter.. (i count one-liner size, before wrapping).. btw, you can omit & in &r, can't? and i think you should follow the requirements exactly (rerolling 1's one), to get the statistics right. – mykhal – 2012-12-17T01:39:31.603

Yes, this answer doesn't seem to fit the requirements of the question. Also, you can just edit your previous answer in-place instead of posting a completely new one. People can just click a link if they want to see what changed between edits. – JoeFish – 2012-12-18T21:31:12.733

0

C 222 204 203

204: Updates from ugoren's comment, recycled more global vars, changed D() into a macro to save a return and three pairs of ().

203: Moved the first printf into the for to save a semicolon.

See it run in Codepad

#define D (t=rand()%6)?t:rand()%6
j,i,f[11],s,t;M(a,b,c){t=a<b?a:b;t=c<t?c:t;t=a+b+c-t;}main(){for(;j++<1e6;M(D,D,D),s+=t+2)++f[t];for(printf("avg(%f)\n",s/1e6);i<11;++i)printf("%d: %f\n",i+2,f[i]/1e4);}

#define D (t=rand()%6)?t:rand()%6
j,i,f[11],s,t;
M(a,b,c)
{
    t=a<b?a:b;
    t=c<t?c:t;
    t=a+b+c-t;
}
main()
{
    for(;j++<1e6;M(D,D,D),s+=t+2)
        ++f[t];
    for(printf("avg(%f)\n",s/1e6);i<11;++i)
        printf("%d: %f\n",i+2,f[i]/1e4);
}
avg(9.095219)
2: 0.001600
3: 0.045200
4: 1.100000
5: 2.903400
6: 6.124600
7: 10.112100
8: 15.556000
9: 18.876400
10: 19.358200
11: 16.053800
12: 9.868700
Press any key to continue . . .

JoeFish

Posted 2012-12-14T23:35:56.270

Reputation: 691

Some tips: M can set t directly. Saves return. D can return (m=rand()%6)?m:rand()%6 (or with gcc - rand()%6?:rand()%6. In the first for, move something from the increment to the loop body (saves a comma). Give main a parameter (saves a comma). – ugoren – 2012-12-18T14:56:14.600

Ah thanks! I was looking for ways to use a global in M() but couldn't get my head aroudn it. – JoeFish – 2012-12-18T14:57:33.990

Some more: In M, merge the 2nd and 3rd lines to save an assignment. In the printf, use j as 1e6. You can define main(i) and loop with ++i<13, then i runs from 2 to 12. – ugoren – 2012-12-19T09:00:13.923

0

C - 200

I didn't bother to re-roll on 1, instead I used the probability distribution (1/36 chance of rolling 1, 7/36 chance of rolling anything else). Hopefully this is acceptable. Newline has been inserted for clarity.

#define D 6-rand()%36/7
a,b,c,t,u,w,y[13];
main(v,q){srand(q);for(;v++<=1e6;u=(a=D)<(b=D)?a:b,w+=t=a+b+(c=D)-(u<c?u:c))y[t]++;
printf("avg(%f)\n",w/1e6);for(v=1;++v<13;)printf("%d: %f\n",v,y[v]/1e4);}

After compilation (gcc -O3) - 1 run

avg(9.096896)
2: 0.002200
3: 0.043100
4: 1.093900
5: 2.891000
6: 6.110100
7: 10.091400
8: 15.605000
9: 18.936500
10: 19.258800
11: 16.047100
12: 9.920800

o_o

Posted 2012-12-14T23:35:56.270

Reputation: 251