-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path3-randomDice.js
executable file
·140 lines (126 loc) · 3.24 KB
/
3-randomDice.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
* Using only the function "oneOrTwo()" below (and therefore no other existing function to obtain random),
* code a function "dice()" who return a number between 1 and 6 (a classic dice) with exactly the
* same probability for each number
*/
/**
* Return randomly 1 or 2
* @return {1|2}
*/
function oneOrTwo() {
return Math.floor(Math.random() * 2) + 1
}
// Bad
function diceV1(){
// Not equitable
// obtain 0 = 50%, 1 = 25% and 2 = 25%
const randomIndex = (oneOrTwo() + oneOrTwo()) % 3
// divide the 6 faces in 2 ranges of 3 number to select with result of random3
if (oneOrTwo() === 2) {
return [4, 5, 6][randomIndex]
}
return [1, 2, 3][randomIndex]
}
// Closer
function diceV2() {
const random = Math.ceil((oneOrTwo() * oneOrTwo() * oneOrTwo() * oneOrTwo() * oneOrTwo()) / 4)
let number = oneOrTwo()
if (number === 1 && oneOrTwo() === 2) {
// Obtain 50% for 2 an 25% for 1 and 3
number += 2
}
// 50% of 2 split with 4
if (number === 2 && oneOrTwo() === 2) {
// obtain 25% between 1 and 4
number += 2
}
// probability 65%
if (random === 1 || random === 4) {
// 16,4%
if (number <= 2 && oneOrTwo() === 2) {
number += 4
}
// 16,4%
if (number <= 4 && number > 2 && oneOrTwo() === 2) {
number += 2
}
}
return number;
}
// Contain lost (6% of result = 0)
function diceV3() {
let random = oneOrTwo() * oneOrTwo() * oneOrTwo() * oneOrTwo() * oneOrTwo()
let number = 0 // 6.27% lost
if (random === 4) { // 31.25%
number += oneOrTwo()
} else if(random === 8) { // 31.25%
number += oneOrTwo() + 2
} else if (random === 2 || random === 16) { // 31.25%
number += oneOrTwo() + 4
}
return number
}
/**
* Generate a number between 0 and 2 fairly
* @return {0|1|2}
*/
function random3() {
let number = 0
// Multiply random
// use 12 because is most reliable to obtain equitable repartition
for (let i = 0; i <= 12; i++) {
number += oneOrTwo()
}
// Use module to get repartition between 0 an 3
return number % 3
}
/**
* Best solution
*/
function dice() {
const randomIndex = random3()
// divide the 6 faces in 2 ranges of 3 number to select with result of random3
if (oneOrTwo() === 2) {
return [4, 5, 6][randomIndex]
}
return [1, 2, 3][randomIndex]
}
// More efficient
function dice2(faces = 6) {
let number = 0
// Use double of faces to obtain perfect repartition
for (let i = 1; i <= faces * 2; ++i) {
number += oneOrTwo() * i // multiply by iterator to enlarge range of repartition
}
// Modulo 6 to limit result in range 0 - 5 and + 1 to shift range to 1 - 6
return number % faces + 1
}
function dice3() {
let number = ''
for (let i = 0; i < 3; i++) {
number += (oneOrTwo() % 2)
}
if (number === '000' || number === '111') {
return dice3()
}
return parseInt(number, 2)
}
const results = [
0, // 1
0, // 2
0, // 3
0, // 4
0, // 5
0, // 6
]
// Check 1 millions times to smooth results
const total = 1000000
for (let i = 1; i <= total; i++) {
const result = dice3() - 1
if (typeof results[result] === 'undefined') {
results[result] = 0
}
++results[result]
}
console.log('Probability for 1 Million try')
console.log(results.map((result, i) => `${i + 1}: ${((result / total) * 100).toFixed(2)}`))