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.
data/spec/bunch_spec.rb CHANGED
@@ -1,421 +1,399 @@
1
- require 'games_dice'
2
- require 'helpers'
3
-
4
- describe GamesDice::Bunch do
5
-
6
- describe "dice scheme" do
7
-
8
- before :each do
9
- srand(67809)
10
- end
11
-
12
- describe '1d10' do
13
- let(:bunch) { GamesDice::Bunch.new( :sides => 10, :ndice => 1 ) }
14
-
15
- it "should simulate rolling a ten-sided die" do
16
- [3,2,8,8,5,3,7].each do |expected_total|
17
- bunch.roll.should == expected_total
18
- bunch.result.should == expected_total
19
- end
20
- end
21
-
22
- it "should concisely explain each result" do
23
- ["3", "2", "8", "8"].each do |expected_explain|
24
- bunch.roll
25
- bunch.explain_result.should == expected_explain
26
- end
27
- end
28
-
29
- it "should calculate correct min, max = 1,10" do
30
- bunch.min.should == 1
31
- bunch.max.should == 10
32
- end
33
-
34
- it "should have a mean value of 5.5" do
35
- bunch.probabilities.expected.should be_within(1e-10).of 5.5
36
- end
37
-
38
- it "should calculate probabilities correctly" do
39
- prob_hash = bunch.probabilities.to_h
40
- prob_hash[1].should be_within(1e-10).of 0.1
41
- prob_hash[2].should be_within(1e-10).of 0.1
42
- prob_hash[3].should be_within(1e-10).of 0.1
43
- prob_hash[4].should be_within(1e-10).of 0.1
44
- prob_hash[5].should be_within(1e-10).of 0.1
45
- prob_hash[6].should be_within(1e-10).of 0.1
46
- prob_hash[7].should be_within(1e-10).of 0.1
47
- prob_hash[8].should be_within(1e-10).of 0.1
48
- prob_hash[9].should be_within(1e-10).of 0.1
49
- prob_hash[10].should be_within(1e-10).of 0.1
50
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
51
- end
52
- end
53
-
54
- describe '2d6' do
55
- let(:bunch) { GamesDice::Bunch.new( :sides => 6, :ndice => 2 ) }
56
-
57
- it "should simulate rolling two six-sided dice and adding them" do
58
- [9,6,11,9,7,7,10].each do |expected_total|
59
- bunch.roll.should == expected_total
60
- bunch.result.should == expected_total
61
- end
62
- end
63
-
64
- it "should concisely explain each result" do
65
- ["3 + 6 = 9","2 + 4 = 6","5 + 6 = 11","3 + 6 = 9","2 + 5 = 7","6 + 1 = 7","5 + 5 = 10",].each do |expected_explain|
66
- bunch.roll
67
- bunch.explain_result.should == expected_explain
68
- end
69
- end
70
-
71
- it "should calculate correct min, max = 2,12" do
72
- bunch.min.should == 2
73
- bunch.max.should == 12
74
- end
75
-
76
- it "should have a mean value of 7.0" do
77
- bunch.probabilities.expected.should 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
- prob_hash[2].should be_within(1e-10).of 1/36.0
83
- prob_hash[3].should be_within(1e-10).of 2/36.0
84
- prob_hash[4].should be_within(1e-10).of 3/36.0
85
- prob_hash[5].should be_within(1e-10).of 4/36.0
86
- prob_hash[6].should be_within(1e-10).of 5/36.0
87
- prob_hash[7].should be_within(1e-10).of 6/36.0
88
- prob_hash[8].should be_within(1e-10).of 5/36.0
89
- prob_hash[9].should be_within(1e-10).of 4/36.0
90
- prob_hash[10].should be_within(1e-10).of 3/36.0
91
- prob_hash[11].should be_within(1e-10).of 2/36.0
92
- prob_hash[12].should be_within(1e-10).of 1/36.0
93
- prob_hash.values.inject(:+).should 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
- bunch.roll.should == expected_total
103
- bunch.result.should == expected_total
104
- end
105
- end
106
-
107
- it "should concisely explain each result" do
108
- ["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
- ].each do |expected_explain|
112
- bunch.roll
113
- bunch.explain_result.should == expected_explain
114
- end
115
- end
116
-
117
- it "should calculate correct min, max = 20,200" do
118
- bunch.min.should == 20
119
- bunch.max.should == 200
120
- end
121
-
122
- it "should have a mean value of 110.0" do
123
- bunch.probabilities.expected.should be_within(1e-8).of 110.0
124
- end
125
-
126
- it "should calculate probabilities correctly" do
127
- prob_hash = bunch.probabilities.to_h
128
- prob_hash[20].should be_within(1e-26).of 1e-20
129
- prob_hash[110].should be_within(1e-10).of 0.0308191892
130
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
131
- end
132
- end
133
-
134
- describe '4d6 keep best 3' do
135
- let(:bunch) { GamesDice::Bunch.new( :sides => 6, :ndice => 4, :keep_mode => :keep_best, :keep_number => 3 ) }
136
-
137
- it "should simulate rolling four six-sided dice and adding the best three values" do
138
- [13,17,13,12,13,10,14].each do |expected_total|
139
- bunch.roll.should == expected_total
140
- bunch.result.should == expected_total
141
- end
142
- end
143
-
144
- it "should concisely explain each result" do
145
- ["3, 6, 2, 4. Keep: 3 + 4 + 6 = 13",
146
- "5, 6, 3, 6. Keep: 5 + 6 + 6 = 17",
147
- "2, 5, 6, 1. Keep: 2 + 5 + 6 = 13",
148
- "5, 5, 2, 1. Keep: 2 + 5 + 5 = 12",
149
- ].each do |expected_explain|
150
- bunch.roll
151
- bunch.explain_result.should == expected_explain
152
- end
153
- end
154
-
155
- it "should calculate correct min, max = 3,18" do
156
- bunch.min.should == 3
157
- bunch.max.should == 18
158
- end
159
-
160
- it "should have a mean value of roughly 12.2446" do
161
- bunch.probabilities.expected.should 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
- prob_hash[3].should be_within(1e-10).of 1/1296.0
167
- prob_hash[4].should be_within(1e-10).of 4/1296.0
168
- prob_hash[5].should be_within(1e-10).of 10/1296.0
169
- prob_hash[6].should be_within(1e-10).of 21/1296.0
170
- prob_hash[7].should be_within(1e-10).of 38/1296.0
171
- prob_hash[8].should be_within(1e-10).of 62/1296.0
172
- prob_hash[9].should be_within(1e-10).of 91/1296.0
173
- prob_hash[10].should be_within(1e-10).of 122/1296.0
174
- prob_hash[11].should be_within(1e-10).of 148/1296.0
175
- prob_hash[12].should be_within(1e-10).of 167/1296.0
176
- prob_hash[13].should be_within(1e-10).of 172/1296.0
177
- prob_hash[14].should be_within(1e-10).of 160/1296.0
178
- prob_hash[15].should be_within(1e-10).of 131/1296.0
179
- prob_hash[16].should be_within(1e-10).of 94/1296.0
180
- prob_hash[17].should be_within(1e-10).of 54/1296.0
181
- prob_hash[18].should be_within(1e-10).of 21/1296.0
182
- prob_hash.values.inject(:+).should 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
- bunch.roll.should == expected_total
192
- bunch.result.should == 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",
201
- ].each do |expected_explain|
202
- bunch.roll
203
- bunch.explain_result.should == expected_explain
204
- end
205
- end
206
-
207
- it "should calculate correct min, max = 1,10" do
208
- bunch.min.should == 1
209
- bunch.max.should == 10
210
- end
211
-
212
- it "should have a mean value of roughly 1.491" do
213
- bunch.probabilities.expected.should be_within(1e-9).of 1.4914341925
214
- end
215
-
216
- it "should calculate probabilities correctly" do
217
- prob_hash = bunch.probabilities.to_h
218
- prob_hash[1].should be_within(1e-10).of 0.6513215599
219
- prob_hash[2].should be_within(1e-10).of 0.2413042577
220
- prob_hash[3].should be_within(1e-10).of 0.0791266575
221
- prob_hash[4].should be_within(1e-10).of 0.0222009073
222
- prob_hash[5].should be_within(1e-10).of 0.0050700551
223
- prob_hash[6].should be_within(1e-10).of 0.0008717049
224
- prob_hash[7].should be_within(1e-10).of 0.0000989527
225
- prob_hash[8].should be_within(1e-10).of 0.0000058025
226
- prob_hash[9].should be_within(1e-10).of 0.0000001023
227
- prob_hash[10].should be_within(1e-18).of 1e-10
228
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
229
- end
230
- end
231
-
232
- describe '5d10, re-roll and add on 10s, keep best 2' do
233
- let(:bunch) {
234
- GamesDice::Bunch.new(
235
- :sides => 10, :ndice => 5, :keep_mode => :keep_best, :keep_number => 2,
236
- :rerolls => [GamesDice::RerollRule.new(10,:==,:reroll_add)]
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.should == expected_total
242
- bunch.result.should == 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",
251
- ].each do |expected_explain|
252
- bunch.roll
253
- bunch.explain_result.should == expected_explain
254
- end
255
- end
256
-
257
- it "should calculate correct min, max = 2, > 100" do
258
- bunch.min.should == 2
259
- bunch.max.should > 100
260
- end
261
-
262
- it "should have a mean value of roughly 18.986" do
263
- bunch.probabilities.expected.should be_within(1e-9).of 18.9859925804
264
- end
265
-
266
- it "should calculate probabilities correctly" do
267
- prob_hash = bunch.probabilities.to_h
268
- prob_hash[2].should be_within(1e-10).of 0.00001
269
- prob_hash[3].should be_within(1e-10).of 0.00005
270
- prob_hash[4].should be_within(1e-10).of 0.00031
271
- prob_hash[5].should be_within(1e-10).of 0.00080
272
- prob_hash[6].should be_within(1e-10).of 0.00211
273
- prob_hash[7].should be_within(1e-10).of 0.00405
274
- prob_hash[8].should be_within(1e-10).of 0.00781
275
- prob_hash[9].should be_within(1e-10).of 0.01280
276
- prob_hash[10].should be_within(1e-10).of 0.02101
277
- prob_hash[12].should be_within(1e-10).of 0.045715
278
- prob_hash[13].should be_within(1e-10).of 0.060830
279
- prob_hash[14].should be_within(1e-10).of 0.077915
280
- prob_hash[15].should be_within(1e-10).of 0.090080
281
- prob_hash[16].should be_within(1e-10).of 0.097935
282
- prob_hash[17].should be_within(1e-10).of 0.091230
283
- prob_hash[18].should be_within(1e-10).of 0.070015
284
- prob_hash[19].should be_within(1e-10).of 0.020480
285
- prob_hash[20].should be_within(1e-10).of 0.032805
286
- prob_hash[22].should be_within(1e-10).of 0.0334626451
287
- prob_hash[23].should be_within(1e-10).of 0.0338904805
288
- prob_hash[24].should be_within(1e-10).of 0.0338098781
289
- prob_hash[25].should be_within(1e-10).of 0.0328226480
290
- prob_hash[26].should be_within(1e-10).of 0.0304393461
291
- prob_hash[27].should be_within(1e-10).of 0.0260456005
292
- prob_hash[28].should be_within(1e-10).of 0.0189361531
293
- prob_hash[29].should be_within(1e-10).of 0.0082804480
294
- prob_hash[30].should be_within(1e-10).of 0.0103524151
295
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
296
- end
297
- end
298
-
299
- describe 'roll 2d20, keep best value' do
300
- let(:bunch) do
301
- GamesDice::Bunch.new(
302
- :sides => 20, :ndice => 2, :keep_mode => :keep_best, :keep_number => 1
303
- )
304
- end
305
-
306
- it "should simulate rolling two twenty-sided dice and keeping the best value" do
307
- [19,18,14,6,13,10,16].each do |expected_total|
308
- bunch.roll.should == expected_total
309
- bunch.result.should == expected_total
310
- end
311
- end
312
-
313
- it "should concisely explain each result" do
314
- ["19, 14. Keep: 19",
315
- "18, 16. Keep: 18",
316
- "5, 14. Keep: 14",
317
- "3, 6. Keep: 6",
318
- ].each do |expected_explain|
319
- bunch.roll
320
- bunch.explain_result.should == expected_explain
321
- end
322
- end
323
-
324
- it "should calculate correct min, max = 1,20" do
325
- bunch.min.should == 1
326
- bunch.max.should == 20
327
- end
328
-
329
- it "should have a mean value of 13.825" do
330
- bunch.probabilities.expected.should be_within(1e-9).of 13.825
331
- end
332
-
333
- it "should calculate probabilities correctly" do
334
- prob_hash = bunch.probabilities.to_h
335
- prob_hash[1].should be_within(1e-10).of 1/400.0
336
- prob_hash[2].should be_within(1e-10).of 3/400.0
337
- prob_hash[3].should be_within(1e-10).of 5/400.0
338
- prob_hash[4].should be_within(1e-10).of 7/400.0
339
- prob_hash[5].should be_within(1e-10).of 9/400.0
340
- prob_hash[6].should be_within(1e-10).of 11/400.0
341
- prob_hash[7].should be_within(1e-10).of 13/400.0
342
- prob_hash[8].should be_within(1e-10).of 15/400.0
343
- prob_hash[9].should be_within(1e-10).of 17/400.0
344
- prob_hash[10].should be_within(1e-10).of 19/400.0
345
- prob_hash[11].should be_within(1e-10).of 21/400.0
346
- prob_hash[12].should be_within(1e-10).of 23/400.0
347
- prob_hash[13].should be_within(1e-10).of 25/400.0
348
- prob_hash[14].should be_within(1e-10).of 27/400.0
349
- prob_hash[15].should be_within(1e-10).of 29/400.0
350
- prob_hash[16].should be_within(1e-10).of 31/400.0
351
- prob_hash[17].should be_within(1e-10).of 33/400.0
352
- prob_hash[18].should be_within(1e-10).of 35/400.0
353
- prob_hash[19].should be_within(1e-10).of 37/400.0
354
- prob_hash[20].should be_within(1e-10).of 39/400.0
355
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
356
- end
357
- end
358
-
359
- describe 'roll 2d20, keep worst value' do
360
- let(:bunch) do
361
- GamesDice::Bunch.new(
362
- :sides => 20, :ndice => 2, :keep_mode => :keep_worst, :keep_number => 1
363
- )
364
- end
365
-
366
- it "should simulate rolling two twenty-sided dice and keeping the best value" do
367
- [14,16,5,3,7,5,9].each do |expected_total|
368
- bunch.roll.should == expected_total
369
- bunch.result.should == expected_total
370
- end
371
- end
372
-
373
- it "should concisely explain each result" do
374
- ["19, 14. Keep: 14",
375
- "18, 16. Keep: 16",
376
- "5, 14. Keep: 5",
377
- "3, 6. Keep: 3",
378
- ].each do |expected_explain|
379
- bunch.roll
380
- bunch.explain_result.should == expected_explain
381
- end
382
- end
383
-
384
- it "should calculate correct min, max = 1,20" do
385
- bunch.min.should == 1
386
- bunch.max.should == 20
387
- end
388
-
389
- it "should have a mean value of 7.175" do
390
- bunch.probabilities.expected.should be_within(1e-9).of 7.175
391
- end
392
-
393
- it "should calculate probabilities correctly" do
394
- prob_hash = bunch.probabilities.to_h
395
- prob_hash[1].should be_within(1e-10).of 39/400.0
396
- prob_hash[2].should be_within(1e-10).of 37/400.0
397
- prob_hash[3].should be_within(1e-10).of 35/400.0
398
- prob_hash[4].should be_within(1e-10).of 33/400.0
399
- prob_hash[5].should be_within(1e-10).of 31/400.0
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