Seven-sided dice from five-sided dice: Difference between revisions

From Rosetta Code
Content added Content deleted
m (Fix links)
Line 10: Line 10:


<small>(Task adapted from an answer [http://stackoverflow.com/questions/90715/what-are-the-best-programming-puzzles-you-came-across here])</small>
<small>(Task adapted from an answer [http://stackoverflow.com/questions/90715/what-are-the-best-programming-puzzles-you-came-across here])</small>
=={{header|OCaml}}==
<lang ocaml>let dice5() = 1 + Random.int 5 ;;

let dice7 =
let rolls2answer = ref [] in
let n = ref 0 in
for roll1 = 1 to 5 do
for roll2 = 1 to 5 do
rolls2answer := ((roll1,roll2), (!n / 3) +1) :: !rolls2answer;
incr n
done;
done;
let rec aux() =
let trial = List.assoc (dice5(),dice5()) !rolls2answer in
if trial <= 7 then trial else aux()
in
aux
;;</lang>

=={{header|Python}}==
=={{header|Python}}==
Follows the method suggested in the task description for creating dice7, and uses a function creator for dice7, to calculate the binning of the two calls to dice5.
Follows the method suggested in the task description for creating dice7, and uses a function creator for dice7, to calculate the binning of the two calls to dice5.

Revision as of 20:21, 9 August 2009

Task
Seven-sided dice from five-sided dice
You are encouraged to solve this task according to the task description, using any language you may know.

Given an equal-probability generator of one of the integers 1 to 5 as dice5; create dice7 that generates a pseudo-random integer from 1 to 7 in equal probability using only dice5 as a source of random numbers, and check the distribution for at least 1000000 calls using the function created in Simple Random Distribution Checker.

dice7 might call dice5 twice, re-call if four of the 25 combinations are given, otherwise split the other 21 combinations into 7 groups of three, and return the group index from the rolls.

(Task adapted from an answer here)

OCaml

<lang ocaml>let dice5() = 1 + Random.int 5 ;;

let dice7 =

 let rolls2answer = ref [] in
 let n = ref 0 in
 for roll1 = 1 to 5 do
   for roll2 = 1 to 5 do
     rolls2answer := ((roll1,roll2), (!n / 3) +1) :: !rolls2answer;
     incr n
   done;
 done;
 let rec aux() =
   let trial = List.assoc (dice5(),dice5()) !rolls2answer in
   if trial <= 7 then trial else aux()
 in
 aux
</lang>

Python

Follows the method suggested in the task description for creating dice7, and uses a function creator for dice7, to calculate the binning of the two calls to dice5. <lang python>import re, random

onetofive = (1,2,3,4,5)

def dice5():

   return random.choice(onetofive)

def dice7generator():

   rolls2answer = {}
   n=0
   for roll1 in onetofive:
       for roll2 in onetofive:
           rolls2answer[(roll1,roll2)] = (n // 3) + 1
           n += 1
   def dice7():
       'Generates 1 to 7 randomly, with equal prob. from dice5'
       trial = rolls2answer[(dice5(), dice5())]
       return trial if trial <=7 else dice7()
   return dice7

dice7 = dice7generator()</lang> Distribution check using Simple Random Distribution Checker:

>>> distcheck(dice5, 1000000, 1)
{1: 200244, 2: 199831, 3: 199548, 4: 199853, 5: 200524}
>>> distcheck(dice7, 1000000, 1)
{1: 142853, 2: 142576, 3: 143067, 4: 142149, 5: 143189, 6: 143285, 7: 142881}

Tcl

Any old D&D hand will know these as a D5 and a D7... <lang tcl>proc D5 {} {expr {1 + int(5 * rand())}}

proc D7 {} {

   while 1 {
       set d55 [expr {5 * [D5] + [D5] - 6}]
       if {$d55 < 21} {
           return [expr {$d55 % 7 + 1}]
       }
   }

}</lang> Checking:

% distcheck D5 1000000
1 199893 2 200162 3 200075 4 199630 5 200240
% distcheck D7 1000000
1 143121 2 142383 3 143353 4 142811 5 142172 6 143291 7 142869