games_dice 0.3.9 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +15 -0
- data/.travis.yml +9 -12
- data/CHANGELOG.md +29 -13
- data/Gemfile +2 -0
- data/README.md +5 -5
- data/Rakefile +14 -11
- data/ext/games_dice/extconf.rb +4 -22
- data/ext/games_dice/probabilities.c +1 -1
- data/games_dice.gemspec +26 -28
- data/lib/games_dice/bunch.rb +241 -247
- data/lib/games_dice/complex_die.rb +287 -303
- data/lib/games_dice/complex_die_helpers.rb +68 -0
- data/lib/games_dice/constants.rb +10 -10
- data/lib/games_dice/dice.rb +146 -143
- data/lib/games_dice/die.rb +101 -97
- data/lib/games_dice/die_result.rb +193 -189
- data/lib/games_dice/map_rule.rb +72 -70
- data/lib/games_dice/marshal.rb +18 -13
- data/lib/games_dice/parser.rb +219 -218
- data/lib/games_dice/reroll_rule.rb +76 -77
- data/lib/games_dice/version.rb +3 -1
- data/lib/games_dice.rb +19 -16
- data/spec/bunch_spec.rb +399 -421
- data/spec/complex_die_spec.rb +314 -306
- data/spec/dice_spec.rb +33 -34
- data/spec/die_result_spec.rb +163 -170
- data/spec/die_spec.rb +81 -82
- data/spec/helpers.rb +26 -22
- data/spec/map_rule_spec.rb +40 -44
- data/spec/parser_spec.rb +106 -82
- data/spec/probability_spec.rb +530 -527
- data/spec/readme_spec.rb +404 -384
- data/spec/reroll_rule_spec.rb +40 -44
- metadata +63 -74
- data/lib/games_dice/probabilities.rb +0 -445
data/spec/bunch_spec.rb
CHANGED
@@ -1,421 +1,399 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
describe
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
bunch.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
bunch.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
bunch.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
prob_hash
|
40
|
-
prob_hash[
|
41
|
-
prob_hash[
|
42
|
-
prob_hash[
|
43
|
-
prob_hash[
|
44
|
-
prob_hash[
|
45
|
-
prob_hash[
|
46
|
-
prob_hash[
|
47
|
-
prob_hash[
|
48
|
-
prob_hash[
|
49
|
-
prob_hash
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
bunch.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
bunch.roll
|
67
|
-
bunch.explain_result.
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
it
|
72
|
-
bunch.min.
|
73
|
-
bunch.max.
|
74
|
-
end
|
75
|
-
|
76
|
-
it
|
77
|
-
bunch.probabilities.expected.
|
78
|
-
end
|
79
|
-
|
80
|
-
it
|
81
|
-
prob_hash = bunch.probabilities.to_h
|
82
|
-
prob_hash[2].
|
83
|
-
prob_hash[3].
|
84
|
-
prob_hash[4].
|
85
|
-
prob_hash[5].
|
86
|
-
prob_hash[6].
|
87
|
-
prob_hash[7].
|
88
|
-
prob_hash[8].
|
89
|
-
prob_hash[9].
|
90
|
-
prob_hash[10].
|
91
|
-
prob_hash[11].
|
92
|
-
prob_hash[12].
|
93
|
-
prob_hash.values.inject(:+).
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
describe '20d10' do
|
98
|
-
let(:bunch) { GamesDice::Bunch.new(
|
99
|
-
|
100
|
-
it
|
101
|
-
[132,103,102,124,132,96,111].each do |expected_total|
|
102
|
-
bunch.roll.
|
103
|
-
bunch.result.
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
it
|
108
|
-
[
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
bunch.
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
bunch.
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
prob_hash
|
129
|
-
prob_hash[
|
130
|
-
prob_hash
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
bunch.
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
].each do |expected_explain|
|
150
|
-
bunch.roll
|
151
|
-
bunch.explain_result.
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
it
|
156
|
-
bunch.min.
|
157
|
-
bunch.max.
|
158
|
-
end
|
159
|
-
|
160
|
-
it
|
161
|
-
bunch.probabilities.expected.
|
162
|
-
end
|
163
|
-
|
164
|
-
it
|
165
|
-
prob_hash = bunch.probabilities.to_h
|
166
|
-
prob_hash[3].
|
167
|
-
prob_hash[4].
|
168
|
-
prob_hash[5].
|
169
|
-
prob_hash[6].
|
170
|
-
prob_hash[7].
|
171
|
-
prob_hash[8].
|
172
|
-
prob_hash[9].
|
173
|
-
prob_hash[10].
|
174
|
-
prob_hash[11].
|
175
|
-
prob_hash[12].
|
176
|
-
prob_hash[13].
|
177
|
-
prob_hash[14].
|
178
|
-
prob_hash[15].
|
179
|
-
prob_hash[16].
|
180
|
-
prob_hash[17].
|
181
|
-
prob_hash[18].
|
182
|
-
prob_hash.values.inject(:+).
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
describe '10d10 keep worst one' do
|
187
|
-
let(:bunch) { GamesDice::Bunch.new(
|
188
|
-
|
189
|
-
it
|
190
|
-
[2,5,1,2,1,1,2].each do |expected_total|
|
191
|
-
bunch.roll.
|
192
|
-
bunch.result.
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
it
|
197
|
-
[
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
bunch.
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
bunch.
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
prob_hash
|
218
|
-
prob_hash[
|
219
|
-
prob_hash[
|
220
|
-
prob_hash[
|
221
|
-
prob_hash[
|
222
|
-
prob_hash[
|
223
|
-
prob_hash[
|
224
|
-
prob_hash[
|
225
|
-
prob_hash[
|
226
|
-
prob_hash[
|
227
|
-
prob_hash
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
:
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
it "should simulate rolling five ten-sided 'exploding' dice and adding the best two values" do
|
240
|
-
[16,24,17,28,12,21,16].each do |expected_total|
|
241
|
-
bunch.roll.
|
242
|
-
bunch.result.
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
it
|
247
|
-
[
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
bunch.
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
bunch.
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
prob_hash
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
prob_hash
|
335
|
-
prob_hash[
|
336
|
-
prob_hash
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
end
|
372
|
-
|
373
|
-
it
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
prob_hash
|
395
|
-
prob_hash
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
prob_hash[6].should be_within(1e-10).of 29/400.0
|
401
|
-
prob_hash[7].should be_within(1e-10).of 27/400.0
|
402
|
-
prob_hash[8].should be_within(1e-10).of 25/400.0
|
403
|
-
prob_hash[9].should be_within(1e-10).of 23/400.0
|
404
|
-
prob_hash[10].should be_within(1e-10).of 21/400.0
|
405
|
-
prob_hash[11].should be_within(1e-10).of 19/400.0
|
406
|
-
prob_hash[12].should be_within(1e-10).of 17/400.0
|
407
|
-
prob_hash[13].should be_within(1e-10).of 15/400.0
|
408
|
-
prob_hash[14].should be_within(1e-10).of 13/400.0
|
409
|
-
prob_hash[15].should be_within(1e-10).of 11/400.0
|
410
|
-
prob_hash[16].should be_within(1e-10).of 9/400.0
|
411
|
-
prob_hash[17].should be_within(1e-10).of 7/400.0
|
412
|
-
prob_hash[18].should be_within(1e-10).of 5/400.0
|
413
|
-
prob_hash[19].should be_within(1e-10).of 3/400.0
|
414
|
-
prob_hash[20].should be_within(1e-10).of 1/400.0
|
415
|
-
prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
|
416
|
-
end
|
417
|
-
end
|
418
|
-
|
419
|
-
end
|
420
|
-
|
421
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'helpers'
|
4
|
+
|
5
|
+
describe GamesDice::Bunch do
|
6
|
+
describe 'dice scheme' do
|
7
|
+
before :each do
|
8
|
+
srand(67_809)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '1d10' do
|
12
|
+
let(:bunch) { GamesDice::Bunch.new(sides: 10, ndice: 1) }
|
13
|
+
|
14
|
+
it 'should simulate rolling a ten-sided die' do
|
15
|
+
[3, 2, 8, 8, 5, 3, 7].each do |expected_total|
|
16
|
+
expect(bunch.roll).to eql expected_total
|
17
|
+
expect(bunch.result).to eql expected_total
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should concisely explain each result' do
|
22
|
+
%w[3 2 8 8].each do |expected_explain|
|
23
|
+
bunch.roll
|
24
|
+
expect(bunch.explain_result).to eql expected_explain
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should calculate correct min, max = 1,10' do
|
29
|
+
expect(bunch.min).to eql 1
|
30
|
+
expect(bunch.max).to eql 10
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should have a mean value of 5.5' do
|
34
|
+
expect(bunch.probabilities.expected).to be_within(1e-10).of 5.5
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should calculate probabilities correctly' do
|
38
|
+
prob_hash = bunch.probabilities.to_h
|
39
|
+
expect(prob_hash[1]).to be_within(1e-10).of 0.1
|
40
|
+
expect(prob_hash[2]).to be_within(1e-10).of 0.1
|
41
|
+
expect(prob_hash[3]).to be_within(1e-10).of 0.1
|
42
|
+
expect(prob_hash[4]).to be_within(1e-10).of 0.1
|
43
|
+
expect(prob_hash[5]).to be_within(1e-10).of 0.1
|
44
|
+
expect(prob_hash[6]).to be_within(1e-10).of 0.1
|
45
|
+
expect(prob_hash[7]).to be_within(1e-10).of 0.1
|
46
|
+
expect(prob_hash[8]).to be_within(1e-10).of 0.1
|
47
|
+
expect(prob_hash[9]).to be_within(1e-10).of 0.1
|
48
|
+
expect(prob_hash[10]).to be_within(1e-10).of 0.1
|
49
|
+
expect(prob_hash.values.inject(:+)).to be_within(1e-9).of 1.0
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '2d6' do
|
54
|
+
let(:bunch) { GamesDice::Bunch.new(sides: 6, ndice: 2) }
|
55
|
+
|
56
|
+
it 'should simulate rolling two six-sided dice and adding them' do
|
57
|
+
[9, 6, 11, 9, 7, 7, 10].each do |expected_total|
|
58
|
+
expect(bunch.roll).to eql expected_total
|
59
|
+
expect(bunch.result).to eql expected_total
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should concisely explain each result' do
|
64
|
+
['3 + 6 = 9', '2 + 4 = 6', '5 + 6 = 11', '3 + 6 = 9', '2 + 5 = 7', '6 + 1 = 7',
|
65
|
+
'5 + 5 = 10'].each do |expected_explain|
|
66
|
+
bunch.roll
|
67
|
+
expect(bunch.explain_result).to eql expected_explain
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should calculate correct min, max = 2,12' do
|
72
|
+
expect(bunch.min).to eql 2
|
73
|
+
expect(bunch.max).to eql 12
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should have a mean value of 7.0' do
|
77
|
+
expect(bunch.probabilities.expected).to be_within(1e-10).of 7.0
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should calculate probabilities correctly' do
|
81
|
+
prob_hash = bunch.probabilities.to_h
|
82
|
+
expect(prob_hash[2]).to be_within(1e-10).of 1 / 36.0
|
83
|
+
expect(prob_hash[3]).to be_within(1e-10).of 2 / 36.0
|
84
|
+
expect(prob_hash[4]).to be_within(1e-10).of 3 / 36.0
|
85
|
+
expect(prob_hash[5]).to be_within(1e-10).of 4 / 36.0
|
86
|
+
expect(prob_hash[6]).to be_within(1e-10).of 5 / 36.0
|
87
|
+
expect(prob_hash[7]).to be_within(1e-10).of 6 / 36.0
|
88
|
+
expect(prob_hash[8]).to be_within(1e-10).of 5 / 36.0
|
89
|
+
expect(prob_hash[9]).to be_within(1e-10).of 4 / 36.0
|
90
|
+
expect(prob_hash[10]).to be_within(1e-10).of 3 / 36.0
|
91
|
+
expect(prob_hash[11]).to be_within(1e-10).of 2 / 36.0
|
92
|
+
expect(prob_hash[12]).to be_within(1e-10).of 1 / 36.0
|
93
|
+
expect(prob_hash.values.inject(:+)).to be_within(1e-9).of 1.0
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '20d10' do
|
98
|
+
let(:bunch) { GamesDice::Bunch.new(sides: 10, ndice: 20) }
|
99
|
+
|
100
|
+
it 'should simulate rolling twenty ten-sided dice and adding them' do
|
101
|
+
[132, 103, 102, 124, 132, 96, 111].each do |expected_total|
|
102
|
+
expect(bunch.roll).to eql expected_total
|
103
|
+
expect(bunch.result).to eql expected_total
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should concisely explain each result' do
|
108
|
+
explains = ['3 + 2 + 8 + 8 + 5 + 3 + 7 + 7 + 6 + 10 + 7 + 6 + 9 + 5 + 5 + 8 + 10 + 9 + 5 + 9 = 132',
|
109
|
+
'3 + 9 + 1 + 4 + 3 + 5 + 7 + 1 + 10 + 4 + 7 + 7 + 6 + 5 + 2 + 7 + 4 + 9 + 7 + 2 = 103',
|
110
|
+
'6 + 1 + 1 + 3 + 1 + 4 + 9 + 6 + 3 + 10 + 9 + 10 + 8 + 4 + 1 + 4 + 2 + 1 + 10 + 9 = 102']
|
111
|
+
|
112
|
+
explains.each do |expected_explain|
|
113
|
+
bunch.roll
|
114
|
+
expect(bunch.explain_result).to eql expected_explain
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should calculate correct min, max = 20,200' do
|
119
|
+
expect(bunch.min).to eql 20
|
120
|
+
expect(bunch.max).to eql 200
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should have a mean value of 110.0' do
|
124
|
+
expect(bunch.probabilities.expected).to be_within(1e-8).of 110.0
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should calculate probabilities correctly' do
|
128
|
+
prob_hash = bunch.probabilities.to_h
|
129
|
+
expect(prob_hash[20]).to be_within(1e-26).of 1e-20
|
130
|
+
expect(prob_hash[110]).to be_within(1e-10).of 0.0308191892
|
131
|
+
expect(prob_hash.values.inject(:+)).to be_within(1e-9).of 1.0
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe '4d6 keep best 3' do
|
136
|
+
let(:bunch) { GamesDice::Bunch.new(sides: 6, ndice: 4, keep_mode: :keep_best, keep_number: 3) }
|
137
|
+
|
138
|
+
it 'should simulate rolling four six-sided dice and adding the best three values' do
|
139
|
+
[13, 17, 13, 12, 13, 10, 14].each do |expected_total|
|
140
|
+
expect(bunch.roll).to eql expected_total
|
141
|
+
expect(bunch.result).to eql expected_total
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should concisely explain each result' do
|
146
|
+
['3, 6, 2, 4. Keep: 3 + 4 + 6 = 13',
|
147
|
+
'5, 6, 3, 6. Keep: 5 + 6 + 6 = 17',
|
148
|
+
'2, 5, 6, 1. Keep: 2 + 5 + 6 = 13',
|
149
|
+
'5, 5, 2, 1. Keep: 2 + 5 + 5 = 12'].each do |expected_explain|
|
150
|
+
bunch.roll
|
151
|
+
expect(bunch.explain_result).to eql expected_explain
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should calculate correct min, max = 3,18' do
|
156
|
+
expect(bunch.min).to eql 3
|
157
|
+
expect(bunch.max).to eql 18
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'should have a mean value of roughly 12.2446' do
|
161
|
+
expect(bunch.probabilities.expected).to be_within(1e-9).of 12.244598765
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should calculate probabilities correctly' do
|
165
|
+
prob_hash = bunch.probabilities.to_h
|
166
|
+
expect(prob_hash[3]).to be_within(1e-10).of 1 / 1296.0
|
167
|
+
expect(prob_hash[4]).to be_within(1e-10).of 4 / 1296.0
|
168
|
+
expect(prob_hash[5]).to be_within(1e-10).of 10 / 1296.0
|
169
|
+
expect(prob_hash[6]).to be_within(1e-10).of 21 / 1296.0
|
170
|
+
expect(prob_hash[7]).to be_within(1e-10).of 38 / 1296.0
|
171
|
+
expect(prob_hash[8]).to be_within(1e-10).of 62 / 1296.0
|
172
|
+
expect(prob_hash[9]).to be_within(1e-10).of 91 / 1296.0
|
173
|
+
expect(prob_hash[10]).to be_within(1e-10).of 122 / 1296.0
|
174
|
+
expect(prob_hash[11]).to be_within(1e-10).of 148 / 1296.0
|
175
|
+
expect(prob_hash[12]).to be_within(1e-10).of 167 / 1296.0
|
176
|
+
expect(prob_hash[13]).to be_within(1e-10).of 172 / 1296.0
|
177
|
+
expect(prob_hash[14]).to be_within(1e-10).of 160 / 1296.0
|
178
|
+
expect(prob_hash[15]).to be_within(1e-10).of 131 / 1296.0
|
179
|
+
expect(prob_hash[16]).to be_within(1e-10).of 94 / 1296.0
|
180
|
+
expect(prob_hash[17]).to be_within(1e-10).of 54 / 1296.0
|
181
|
+
expect(prob_hash[18]).to be_within(1e-10).of 21 / 1296.0
|
182
|
+
expect(prob_hash.values.inject(:+)).to be_within(1e-9).of 1.0
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe '10d10 keep worst one' do
|
187
|
+
let(:bunch) { GamesDice::Bunch.new(sides: 10, ndice: 10, keep_mode: :keep_worst, keep_number: 1) }
|
188
|
+
|
189
|
+
it 'should simulate rolling ten ten-sided dice and keeping the worst value' do
|
190
|
+
[2, 5, 1, 2, 1, 1, 2].each do |expected_total|
|
191
|
+
expect(bunch.roll).to eql expected_total
|
192
|
+
expect(bunch.result).to eql expected_total
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should concisely explain each result' do
|
197
|
+
['3, 2, 8, 8, 5, 3, 7, 7, 6, 10. Keep: 2',
|
198
|
+
'7, 6, 9, 5, 5, 8, 10, 9, 5, 9. Keep: 5',
|
199
|
+
'3, 9, 1, 4, 3, 5, 7, 1, 10, 4. Keep: 1',
|
200
|
+
'7, 7, 6, 5, 2, 7, 4, 9, 7, 2. Keep: 2'].each do |expected_explain|
|
201
|
+
bunch.roll
|
202
|
+
expect(bunch.explain_result).to eql expected_explain
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'should calculate correct min, max = 1,10' do
|
207
|
+
expect(bunch.min).to eql 1
|
208
|
+
expect(bunch.max).to eql 10
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should have a mean value of roughly 1.491' do
|
212
|
+
expect(bunch.probabilities.expected).to be_within(1e-9).of 1.4914341925
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'should calculate probabilities correctly' do
|
216
|
+
prob_hash = bunch.probabilities.to_h
|
217
|
+
expect(prob_hash[1]).to be_within(1e-10).of 0.6513215599
|
218
|
+
expect(prob_hash[2]).to be_within(1e-10).of 0.2413042577
|
219
|
+
expect(prob_hash[3]).to be_within(1e-10).of 0.0791266575
|
220
|
+
expect(prob_hash[4]).to be_within(1e-10).of 0.0222009073
|
221
|
+
expect(prob_hash[5]).to be_within(1e-10).of 0.0050700551
|
222
|
+
expect(prob_hash[6]).to be_within(1e-10).of 0.0008717049
|
223
|
+
expect(prob_hash[7]).to be_within(1e-10).of 0.0000989527
|
224
|
+
expect(prob_hash[8]).to be_within(1e-10).of 0.0000058025
|
225
|
+
expect(prob_hash[9]).to be_within(1e-10).of 0.0000001023
|
226
|
+
expect(prob_hash[10]).to be_within(1e-18).of 1e-10
|
227
|
+
expect(prob_hash.values.inject(:+)).to be_within(1e-9).of 1.0
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe '5d10, re-roll and add on 10s, keep best 2' do
|
232
|
+
let(:bunch) do
|
233
|
+
GamesDice::Bunch.new(
|
234
|
+
sides: 10, ndice: 5, keep_mode: :keep_best, keep_number: 2,
|
235
|
+
rerolls: [GamesDice::RerollRule.new(10, :==, :reroll_add)]
|
236
|
+
)
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should simulate rolling five ten-sided 'exploding' dice and adding the best two values" do
|
240
|
+
[16, 24, 17, 28, 12, 21, 16].each do |expected_total|
|
241
|
+
expect(bunch.roll).to eql expected_total
|
242
|
+
expect(bunch.result).to eql expected_total
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'should concisely explain each result' do
|
247
|
+
['3, 2, 8, 8, 5. Keep: 8 + 8 = 16',
|
248
|
+
'3, 7, 7, 6, [10+7] 17. Keep: 7 + 17 = 24',
|
249
|
+
'6, 9, 5, 5, 8. Keep: 8 + 9 = 17',
|
250
|
+
'[10+9] 19, 5, 9, 3, 9. Keep: 9 + 19 = 28'].each do |expected_explain|
|
251
|
+
bunch.roll
|
252
|
+
expect(bunch.explain_result).to eql expected_explain
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'should calculate correct min, max = 2, > 100' do
|
257
|
+
expect(bunch.min).to eql 2
|
258
|
+
expect(bunch.max).to be > 100
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'should have a mean value of roughly 18.986' do
|
262
|
+
expect(bunch.probabilities.expected).to be_within(1e-9).of 18.9859925804
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'should calculate probabilities correctly' do
|
266
|
+
prob_hash = bunch.probabilities.to_h
|
267
|
+
probs = prob_hash.values_at(*2..30)
|
268
|
+
expected_probs = [0.00001, 0.00005, 0.00031, 0.00080, 0.00211, 0.00405, 0.00781, 0.01280, 0.02101, 0.0312,
|
269
|
+
0.045715, 0.060830, 0.077915, 0.090080, 0.097935, 0.091230, 0.070015, 0.020480, 0.032805,
|
270
|
+
0.0328, 0.0334626451, 0.0338904805, 0.0338098781, 0.0328226480, 0.0304393461, 0.0260456005,
|
271
|
+
0.0189361531, 0.0082804480, 0.0103524151]
|
272
|
+
|
273
|
+
probs.zip(expected_probs) do |got_prob, expected_prob|
|
274
|
+
expect(got_prob).to be_within(1e-10).of(expected_prob)
|
275
|
+
end
|
276
|
+
|
277
|
+
expect(prob_hash.values.inject(:+)).to be_within(1e-9).of 1.0
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
describe 'roll 2d20, keep best value' do
|
282
|
+
let(:bunch) do
|
283
|
+
GamesDice::Bunch.new(
|
284
|
+
sides: 20, ndice: 2, keep_mode: :keep_best, keep_number: 1
|
285
|
+
)
|
286
|
+
end
|
287
|
+
|
288
|
+
it 'should simulate rolling two twenty-sided dice and keeping the best value' do
|
289
|
+
[19, 18, 14, 6, 13, 10, 16].each do |expected_total|
|
290
|
+
expect(bunch.roll).to eql expected_total
|
291
|
+
expect(bunch.result).to eql expected_total
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'should concisely explain each result' do
|
296
|
+
['19, 14. Keep: 19',
|
297
|
+
'18, 16. Keep: 18',
|
298
|
+
'5, 14. Keep: 14',
|
299
|
+
'3, 6. Keep: 6'].each do |expected_explain|
|
300
|
+
bunch.roll
|
301
|
+
expect(bunch.explain_result).to eql expected_explain
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'should calculate correct min, max = 1,20' do
|
306
|
+
expect(bunch.min).to eql 1
|
307
|
+
expect(bunch.max).to eql 20
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'should have a mean value of 13.825' do
|
311
|
+
expect(bunch.probabilities.expected).to be_within(1e-9).of 13.825
|
312
|
+
end
|
313
|
+
|
314
|
+
it 'should calculate probabilities correctly' do
|
315
|
+
prob_hash = bunch.probabilities.to_h
|
316
|
+
expect(prob_hash[1]).to be_within(1e-10).of 1 / 400.0
|
317
|
+
expect(prob_hash[2]).to be_within(1e-10).of 3 / 400.0
|
318
|
+
expect(prob_hash[3]).to be_within(1e-10).of 5 / 400.0
|
319
|
+
expect(prob_hash[4]).to be_within(1e-10).of 7 / 400.0
|
320
|
+
expect(prob_hash[5]).to be_within(1e-10).of 9 / 400.0
|
321
|
+
expect(prob_hash[6]).to be_within(1e-10).of 11 / 400.0
|
322
|
+
expect(prob_hash[7]).to be_within(1e-10).of 13 / 400.0
|
323
|
+
expect(prob_hash[8]).to be_within(1e-10).of 15 / 400.0
|
324
|
+
expect(prob_hash[9]).to be_within(1e-10).of 17 / 400.0
|
325
|
+
expect(prob_hash[10]).to be_within(1e-10).of 19 / 400.0
|
326
|
+
expect(prob_hash[11]).to be_within(1e-10).of 21 / 400.0
|
327
|
+
expect(prob_hash[12]).to be_within(1e-10).of 23 / 400.0
|
328
|
+
expect(prob_hash[13]).to be_within(1e-10).of 25 / 400.0
|
329
|
+
expect(prob_hash[14]).to be_within(1e-10).of 27 / 400.0
|
330
|
+
expect(prob_hash[15]).to be_within(1e-10).of 29 / 400.0
|
331
|
+
expect(prob_hash[16]).to be_within(1e-10).of 31 / 400.0
|
332
|
+
expect(prob_hash[17]).to be_within(1e-10).of 33 / 400.0
|
333
|
+
expect(prob_hash[18]).to be_within(1e-10).of 35 / 400.0
|
334
|
+
expect(prob_hash[19]).to be_within(1e-10).of 37 / 400.0
|
335
|
+
expect(prob_hash[20]).to be_within(1e-10).of 39 / 400.0
|
336
|
+
expect(prob_hash.values.inject(:+)).to be_within(1e-9).of 1.0
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
describe 'roll 2d20, keep worst value' do
|
341
|
+
let(:bunch) do
|
342
|
+
GamesDice::Bunch.new(
|
343
|
+
sides: 20, ndice: 2, keep_mode: :keep_worst, keep_number: 1
|
344
|
+
)
|
345
|
+
end
|
346
|
+
|
347
|
+
it 'should simulate rolling two twenty-sided dice and keeping the best value' do
|
348
|
+
[14, 16, 5, 3, 7, 5, 9].each do |expected_total|
|
349
|
+
expect(bunch.roll).to eql expected_total
|
350
|
+
expect(bunch.result).to eql expected_total
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
it 'should concisely explain each result' do
|
355
|
+
['19, 14. Keep: 14',
|
356
|
+
'18, 16. Keep: 16',
|
357
|
+
'5, 14. Keep: 5',
|
358
|
+
'3, 6. Keep: 3'].each do |expected_explain|
|
359
|
+
bunch.roll
|
360
|
+
expect(bunch.explain_result).to eql expected_explain
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
it 'should calculate correct min, max = 1,20' do
|
365
|
+
expect(bunch.min).to eql 1
|
366
|
+
expect(bunch.max).to eql 20
|
367
|
+
end
|
368
|
+
|
369
|
+
it 'should have a mean value of 7.175' do
|
370
|
+
expect(bunch.probabilities.expected).to be_within(1e-9).of 7.175
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'should calculate probabilities correctly' do
|
374
|
+
prob_hash = bunch.probabilities.to_h
|
375
|
+
expect(prob_hash[1]).to be_within(1e-10).of 39 / 400.0
|
376
|
+
expect(prob_hash[2]).to be_within(1e-10).of 37 / 400.0
|
377
|
+
expect(prob_hash[3]).to be_within(1e-10).of 35 / 400.0
|
378
|
+
expect(prob_hash[4]).to be_within(1e-10).of 33 / 400.0
|
379
|
+
expect(prob_hash[5]).to be_within(1e-10).of 31 / 400.0
|
380
|
+
expect(prob_hash[6]).to be_within(1e-10).of 29 / 400.0
|
381
|
+
expect(prob_hash[7]).to be_within(1e-10).of 27 / 400.0
|
382
|
+
expect(prob_hash[8]).to be_within(1e-10).of 25 / 400.0
|
383
|
+
expect(prob_hash[9]).to be_within(1e-10).of 23 / 400.0
|
384
|
+
expect(prob_hash[10]).to be_within(1e-10).of 21 / 400.0
|
385
|
+
expect(prob_hash[11]).to be_within(1e-10).of 19 / 400.0
|
386
|
+
expect(prob_hash[12]).to be_within(1e-10).of 17 / 400.0
|
387
|
+
expect(prob_hash[13]).to be_within(1e-10).of 15 / 400.0
|
388
|
+
expect(prob_hash[14]).to be_within(1e-10).of 13 / 400.0
|
389
|
+
expect(prob_hash[15]).to be_within(1e-10).of 11 / 400.0
|
390
|
+
expect(prob_hash[16]).to be_within(1e-10).of 9 / 400.0
|
391
|
+
expect(prob_hash[17]).to be_within(1e-10).of 7 / 400.0
|
392
|
+
expect(prob_hash[18]).to be_within(1e-10).of 5 / 400.0
|
393
|
+
expect(prob_hash[19]).to be_within(1e-10).of 3 / 400.0
|
394
|
+
expect(prob_hash[20]).to be_within(1e-10).of 1 / 400.0
|
395
|
+
expect(prob_hash.values.inject(:+)).to be_within(1e-9).of 1.0
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|