Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

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

share|improve this question
2  
Are we required to throw random dice, or may we calculate the probabilities directly? –  primo Dec 15 '12 at 6:22
    
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 Dec 15 '12 at 17:09
    
Random of course, and you're right, must is more fun ;) –  Sven Dec 15 '12 at 18:25
    
So, that is roll 3 dice, re-roll the 1s, take away to lowest die, sum the two, and repeat 1mil times? –  TwiNight Jan 3 '13 at 5:34
add comment

14 Answers 14

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). All white spaces, except for that in /. 0, are included only for readability.

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}}}

share|improve this answer
    
In 96: r=RandomInteger;{#[[1]]+2,#[[2]]/10^4}&/@Sort@Tally[Tr/@Rest/@Sort/@(5~r~{10^6,‌​3}/. 0:>r[5])]//N –  belisarius Dec 16 '12 at 16:57
    
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. " –  David Carraher Dec 16 '12 at 17:01
    
r = RandomInteger; {#[[1]] + 2, #[[2]]/10^4} & /@ Sort@Tally[Tr /@ Rest /@ Sort /@ (5~r~{10^6, 3} /. 0 :> r[5])] // N –  belisarius Dec 16 '12 at 17:03
    
And then remove all the spaces except the one before the 0 in /. 0 –  belisarius Dec 16 '12 at 17:04
1  
Works. And about 10000 x faster than mine. Why don't you submit it as your own? –  David Carraher Dec 16 '12 at 17:08
show 2 more comments

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.
share|improve this answer
add comment

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
share|improve this answer
    
Very golfable. r←r+==r+←, ((3↑x)~1)==(1~⍨3↑x), 10*6==1e6, ,[1.1]==,[⍟3] –  TwiNight Jan 3 '13 at 17:29
    
@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 Jan 3 '13 at 22:01
add comment

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
share|improve this answer
    
Please show your results. I'm curious. –  David Carraher Dec 15 '12 at 13:57
add comment

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);}}}}
share|improve this answer
    
please read 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. –  w0lf Dec 15 '12 at 9:23
add comment

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
share|improve this answer
1  
hey, 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 Dec 17 '12 at 1:39
    
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 Dec 18 '12 at 21:31
add comment

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
share|improve this answer
add comment

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 
share|improve this answer
add comment

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

share|improve this answer
add comment

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 ;)

share|improve this answer
    
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. –  David Carraher Dec 15 '12 at 14:02
add comment

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

share|improve this answer
    
Do 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 Dec 16 '12 at 23:06
    
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 Dec 16 '12 at 23:40
3  
You 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 Dec 17 '12 at 2:25
add comment
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
share|improve this answer
add comment

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 . . .
share|improve this answer
    
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 Dec 18 '12 at 14:56
    
Ah thanks! I was looking for ways to use a global in M() but couldn't get my head aroudn it. –  JoeFish Dec 18 '12 at 14:57
    
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 Dec 19 '12 at 9:00
add comment

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
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.