games_dice 0.3.12 → 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,420 +1,399 @@
1
- require 'helpers'
2
-
3
- describe GamesDice::Bunch do
4
-
5
- describe "dice scheme" do
6
-
7
- before :each do
8
- srand(67809)
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
- bunch.roll.should == expected_total
17
- bunch.result.should == expected_total
18
- end
19
- end
20
-
21
- it "should concisely explain each result" do
22
- ["3", "2", "8", "8"].each do |expected_explain|
23
- bunch.roll
24
- bunch.explain_result.should == expected_explain
25
- end
26
- end
27
-
28
- it "should calculate correct min, max = 1,10" do
29
- bunch.min.should == 1
30
- bunch.max.should == 10
31
- end
32
-
33
- it "should have a mean value of 5.5" do
34
- bunch.probabilities.expected.should 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
- prob_hash[1].should be_within(1e-10).of 0.1
40
- prob_hash[2].should be_within(1e-10).of 0.1
41
- prob_hash[3].should be_within(1e-10).of 0.1
42
- prob_hash[4].should be_within(1e-10).of 0.1
43
- prob_hash[5].should be_within(1e-10).of 0.1
44
- prob_hash[6].should be_within(1e-10).of 0.1
45
- prob_hash[7].should be_within(1e-10).of 0.1
46
- prob_hash[8].should be_within(1e-10).of 0.1
47
- prob_hash[9].should be_within(1e-10).of 0.1
48
- prob_hash[10].should be_within(1e-10).of 0.1
49
- prob_hash.values.inject(:+).should 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
- bunch.roll.should == expected_total
59
- bunch.result.should == 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","5 + 5 = 10",].each do |expected_explain|
65
- bunch.roll
66
- bunch.explain_result.should == expected_explain
67
- end
68
- end
69
-
70
- it "should calculate correct min, max = 2,12" do
71
- bunch.min.should == 2
72
- bunch.max.should == 12
73
- end
74
-
75
- it "should have a mean value of 7.0" do
76
- bunch.probabilities.expected.should be_within(1e-10).of 7.0
77
- end
78
-
79
- it "should calculate probabilities correctly" do
80
- prob_hash = bunch.probabilities.to_h
81
- prob_hash[2].should be_within(1e-10).of 1/36.0
82
- prob_hash[3].should be_within(1e-10).of 2/36.0
83
- prob_hash[4].should be_within(1e-10).of 3/36.0
84
- prob_hash[5].should be_within(1e-10).of 4/36.0
85
- prob_hash[6].should be_within(1e-10).of 5/36.0
86
- prob_hash[7].should be_within(1e-10).of 6/36.0
87
- prob_hash[8].should be_within(1e-10).of 5/36.0
88
- prob_hash[9].should be_within(1e-10).of 4/36.0
89
- prob_hash[10].should be_within(1e-10).of 3/36.0
90
- prob_hash[11].should be_within(1e-10).of 2/36.0
91
- prob_hash[12].should be_within(1e-10).of 1/36.0
92
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
93
- end
94
- end
95
-
96
- describe '20d10' do
97
- let(:bunch) { GamesDice::Bunch.new( :sides => 10, :ndice => 20 ) }
98
-
99
- it "should simulate rolling twenty ten-sided dice and adding them" do
100
- [132,103,102,124,132,96,111].each do |expected_total|
101
- bunch.roll.should == expected_total
102
- bunch.result.should == expected_total
103
- end
104
- end
105
-
106
- it "should concisely explain each result" do
107
- ["3 + 2 + 8 + 8 + 5 + 3 + 7 + 7 + 6 + 10 + 7 + 6 + 9 + 5 + 5 + 8 + 10 + 9 + 5 + 9 = 132",
108
- "3 + 9 + 1 + 4 + 3 + 5 + 7 + 1 + 10 + 4 + 7 + 7 + 6 + 5 + 2 + 7 + 4 + 9 + 7 + 2 = 103",
109
- "6 + 1 + 1 + 3 + 1 + 4 + 9 + 6 + 3 + 10 + 9 + 10 + 8 + 4 + 1 + 4 + 2 + 1 + 10 + 9 = 102",
110
- ].each do |expected_explain|
111
- bunch.roll
112
- bunch.explain_result.should == expected_explain
113
- end
114
- end
115
-
116
- it "should calculate correct min, max = 20,200" do
117
- bunch.min.should == 20
118
- bunch.max.should == 200
119
- end
120
-
121
- it "should have a mean value of 110.0" do
122
- bunch.probabilities.expected.should be_within(1e-8).of 110.0
123
- end
124
-
125
- it "should calculate probabilities correctly" do
126
- prob_hash = bunch.probabilities.to_h
127
- prob_hash[20].should be_within(1e-26).of 1e-20
128
- prob_hash[110].should be_within(1e-10).of 0.0308191892
129
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
130
- end
131
- end
132
-
133
- describe '4d6 keep best 3' do
134
- let(:bunch) { GamesDice::Bunch.new( :sides => 6, :ndice => 4, :keep_mode => :keep_best, :keep_number => 3 ) }
135
-
136
- it "should simulate rolling four six-sided dice and adding the best three values" do
137
- [13,17,13,12,13,10,14].each do |expected_total|
138
- bunch.roll.should == expected_total
139
- bunch.result.should == expected_total
140
- end
141
- end
142
-
143
- it "should concisely explain each result" do
144
- ["3, 6, 2, 4. Keep: 3 + 4 + 6 = 13",
145
- "5, 6, 3, 6. Keep: 5 + 6 + 6 = 17",
146
- "2, 5, 6, 1. Keep: 2 + 5 + 6 = 13",
147
- "5, 5, 2, 1. Keep: 2 + 5 + 5 = 12",
148
- ].each do |expected_explain|
149
- bunch.roll
150
- bunch.explain_result.should == expected_explain
151
- end
152
- end
153
-
154
- it "should calculate correct min, max = 3,18" do
155
- bunch.min.should == 3
156
- bunch.max.should == 18
157
- end
158
-
159
- it "should have a mean value of roughly 12.2446" do
160
- bunch.probabilities.expected.should be_within(1e-9).of 12.244598765
161
- end
162
-
163
- it "should calculate probabilities correctly" do
164
- prob_hash = bunch.probabilities.to_h
165
- prob_hash[3].should be_within(1e-10).of 1/1296.0
166
- prob_hash[4].should be_within(1e-10).of 4/1296.0
167
- prob_hash[5].should be_within(1e-10).of 10/1296.0
168
- prob_hash[6].should be_within(1e-10).of 21/1296.0
169
- prob_hash[7].should be_within(1e-10).of 38/1296.0
170
- prob_hash[8].should be_within(1e-10).of 62/1296.0
171
- prob_hash[9].should be_within(1e-10).of 91/1296.0
172
- prob_hash[10].should be_within(1e-10).of 122/1296.0
173
- prob_hash[11].should be_within(1e-10).of 148/1296.0
174
- prob_hash[12].should be_within(1e-10).of 167/1296.0
175
- prob_hash[13].should be_within(1e-10).of 172/1296.0
176
- prob_hash[14].should be_within(1e-10).of 160/1296.0
177
- prob_hash[15].should be_within(1e-10).of 131/1296.0
178
- prob_hash[16].should be_within(1e-10).of 94/1296.0
179
- prob_hash[17].should be_within(1e-10).of 54/1296.0
180
- prob_hash[18].should be_within(1e-10).of 21/1296.0
181
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
182
- end
183
- end
184
-
185
- describe '10d10 keep worst one' do
186
- let(:bunch) { GamesDice::Bunch.new( :sides => 10, :ndice => 10, :keep_mode => :keep_worst, :keep_number => 1 ) }
187
-
188
- it "should simulate rolling ten ten-sided dice and keeping the worst value" do
189
- [2,5,1,2,1,1,2].each do |expected_total|
190
- bunch.roll.should == expected_total
191
- bunch.result.should == expected_total
192
- end
193
- end
194
-
195
- it "should concisely explain each result" do
196
- ["3, 2, 8, 8, 5, 3, 7, 7, 6, 10. Keep: 2",
197
- "7, 6, 9, 5, 5, 8, 10, 9, 5, 9. Keep: 5",
198
- "3, 9, 1, 4, 3, 5, 7, 1, 10, 4. Keep: 1",
199
- "7, 7, 6, 5, 2, 7, 4, 9, 7, 2. Keep: 2",
200
- ].each do |expected_explain|
201
- bunch.roll
202
- bunch.explain_result.should == expected_explain
203
- end
204
- end
205
-
206
- it "should calculate correct min, max = 1,10" do
207
- bunch.min.should == 1
208
- bunch.max.should == 10
209
- end
210
-
211
- it "should have a mean value of roughly 1.491" do
212
- bunch.probabilities.expected.should 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
- prob_hash[1].should be_within(1e-10).of 0.6513215599
218
- prob_hash[2].should be_within(1e-10).of 0.2413042577
219
- prob_hash[3].should be_within(1e-10).of 0.0791266575
220
- prob_hash[4].should be_within(1e-10).of 0.0222009073
221
- prob_hash[5].should be_within(1e-10).of 0.0050700551
222
- prob_hash[6].should be_within(1e-10).of 0.0008717049
223
- prob_hash[7].should be_within(1e-10).of 0.0000989527
224
- prob_hash[8].should be_within(1e-10).of 0.0000058025
225
- prob_hash[9].should be_within(1e-10).of 0.0000001023
226
- prob_hash[10].should be_within(1e-18).of 1e-10
227
- prob_hash.values.inject(:+).should 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) {
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
-
238
- it "should simulate rolling five ten-sided 'exploding' dice and adding the best two values" do
239
- [16,24,17,28,12,21,16].each do |expected_total|
240
- bunch.roll.should == expected_total
241
- bunch.result.should == expected_total
242
- end
243
- end
244
-
245
- it "should concisely explain each result" do
246
- ["3, 2, 8, 8, 5. Keep: 8 + 8 = 16",
247
- "3, 7, 7, 6, [10+7] 17. Keep: 7 + 17 = 24",
248
- "6, 9, 5, 5, 8. Keep: 8 + 9 = 17",
249
- "[10+9] 19, 5, 9, 3, 9. Keep: 9 + 19 = 28",
250
- ].each do |expected_explain|
251
- bunch.roll
252
- bunch.explain_result.should == expected_explain
253
- end
254
- end
255
-
256
- it "should calculate correct min, max = 2, > 100" do
257
- bunch.min.should == 2
258
- bunch.max.should > 100
259
- end
260
-
261
- it "should have a mean value of roughly 18.986" do
262
- bunch.probabilities.expected.should 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
- prob_hash[2].should be_within(1e-10).of 0.00001
268
- prob_hash[3].should be_within(1e-10).of 0.00005
269
- prob_hash[4].should be_within(1e-10).of 0.00031
270
- prob_hash[5].should be_within(1e-10).of 0.00080
271
- prob_hash[6].should be_within(1e-10).of 0.00211
272
- prob_hash[7].should be_within(1e-10).of 0.00405
273
- prob_hash[8].should be_within(1e-10).of 0.00781
274
- prob_hash[9].should be_within(1e-10).of 0.01280
275
- prob_hash[10].should be_within(1e-10).of 0.02101
276
- prob_hash[12].should be_within(1e-10).of 0.045715
277
- prob_hash[13].should be_within(1e-10).of 0.060830
278
- prob_hash[14].should be_within(1e-10).of 0.077915
279
- prob_hash[15].should be_within(1e-10).of 0.090080
280
- prob_hash[16].should be_within(1e-10).of 0.097935
281
- prob_hash[17].should be_within(1e-10).of 0.091230
282
- prob_hash[18].should be_within(1e-10).of 0.070015
283
- prob_hash[19].should be_within(1e-10).of 0.020480
284
- prob_hash[20].should be_within(1e-10).of 0.032805
285
- prob_hash[22].should be_within(1e-10).of 0.0334626451
286
- prob_hash[23].should be_within(1e-10).of 0.0338904805
287
- prob_hash[24].should be_within(1e-10).of 0.0338098781
288
- prob_hash[25].should be_within(1e-10).of 0.0328226480
289
- prob_hash[26].should be_within(1e-10).of 0.0304393461
290
- prob_hash[27].should be_within(1e-10).of 0.0260456005
291
- prob_hash[28].should be_within(1e-10).of 0.0189361531
292
- prob_hash[29].should be_within(1e-10).of 0.0082804480
293
- prob_hash[30].should be_within(1e-10).of 0.0103524151
294
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
295
- end
296
- end
297
-
298
- describe 'roll 2d20, keep best value' do
299
- let(:bunch) do
300
- GamesDice::Bunch.new(
301
- :sides => 20, :ndice => 2, :keep_mode => :keep_best, :keep_number => 1
302
- )
303
- end
304
-
305
- it "should simulate rolling two twenty-sided dice and keeping the best value" do
306
- [19,18,14,6,13,10,16].each do |expected_total|
307
- bunch.roll.should == expected_total
308
- bunch.result.should == expected_total
309
- end
310
- end
311
-
312
- it "should concisely explain each result" do
313
- ["19, 14. Keep: 19",
314
- "18, 16. Keep: 18",
315
- "5, 14. Keep: 14",
316
- "3, 6. Keep: 6",
317
- ].each do |expected_explain|
318
- bunch.roll
319
- bunch.explain_result.should == expected_explain
320
- end
321
- end
322
-
323
- it "should calculate correct min, max = 1,20" do
324
- bunch.min.should == 1
325
- bunch.max.should == 20
326
- end
327
-
328
- it "should have a mean value of 13.825" do
329
- bunch.probabilities.expected.should be_within(1e-9).of 13.825
330
- end
331
-
332
- it "should calculate probabilities correctly" do
333
- prob_hash = bunch.probabilities.to_h
334
- prob_hash[1].should be_within(1e-10).of 1/400.0
335
- prob_hash[2].should be_within(1e-10).of 3/400.0
336
- prob_hash[3].should be_within(1e-10).of 5/400.0
337
- prob_hash[4].should be_within(1e-10).of 7/400.0
338
- prob_hash[5].should be_within(1e-10).of 9/400.0
339
- prob_hash[6].should be_within(1e-10).of 11/400.0
340
- prob_hash[7].should be_within(1e-10).of 13/400.0
341
- prob_hash[8].should be_within(1e-10).of 15/400.0
342
- prob_hash[9].should be_within(1e-10).of 17/400.0
343
- prob_hash[10].should be_within(1e-10).of 19/400.0
344
- prob_hash[11].should be_within(1e-10).of 21/400.0
345
- prob_hash[12].should be_within(1e-10).of 23/400.0
346
- prob_hash[13].should be_within(1e-10).of 25/400.0
347
- prob_hash[14].should be_within(1e-10).of 27/400.0
348
- prob_hash[15].should be_within(1e-10).of 29/400.0
349
- prob_hash[16].should be_within(1e-10).of 31/400.0
350
- prob_hash[17].should be_within(1e-10).of 33/400.0
351
- prob_hash[18].should be_within(1e-10).of 35/400.0
352
- prob_hash[19].should be_within(1e-10).of 37/400.0
353
- prob_hash[20].should be_within(1e-10).of 39/400.0
354
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
355
- end
356
- end
357
-
358
- describe 'roll 2d20, keep worst value' do
359
- let(:bunch) do
360
- GamesDice::Bunch.new(
361
- :sides => 20, :ndice => 2, :keep_mode => :keep_worst, :keep_number => 1
362
- )
363
- end
364
-
365
- it "should simulate rolling two twenty-sided dice and keeping the best value" do
366
- [14,16,5,3,7,5,9].each do |expected_total|
367
- bunch.roll.should == expected_total
368
- bunch.result.should == expected_total
369
- end
370
- end
371
-
372
- it "should concisely explain each result" do
373
- ["19, 14. Keep: 14",
374
- "18, 16. Keep: 16",
375
- "5, 14. Keep: 5",
376
- "3, 6. Keep: 3",
377
- ].each do |expected_explain|
378
- bunch.roll
379
- bunch.explain_result.should == expected_explain
380
- end
381
- end
382
-
383
- it "should calculate correct min, max = 1,20" do
384
- bunch.min.should == 1
385
- bunch.max.should == 20
386
- end
387
-
388
- it "should have a mean value of 7.175" do
389
- bunch.probabilities.expected.should be_within(1e-9).of 7.175
390
- end
391
-
392
- it "should calculate probabilities correctly" do
393
- prob_hash = bunch.probabilities.to_h
394
- prob_hash[1].should be_within(1e-10).of 39/400.0
395
- prob_hash[2].should be_within(1e-10).of 37/400.0
396
- prob_hash[3].should be_within(1e-10).of 35/400.0
397
- prob_hash[4].should be_within(1e-10).of 33/400.0
398
- prob_hash[5].should be_within(1e-10).of 31/400.0
399
- prob_hash[6].should be_within(1e-10).of 29/400.0
400
- prob_hash[7].should be_within(1e-10).of 27/400.0
401
- prob_hash[8].should be_within(1e-10).of 25/400.0
402
- prob_hash[9].should be_within(1e-10).of 23/400.0
403
- prob_hash[10].should be_within(1e-10).of 21/400.0
404
- prob_hash[11].should be_within(1e-10).of 19/400.0
405
- prob_hash[12].should be_within(1e-10).of 17/400.0
406
- prob_hash[13].should be_within(1e-10).of 15/400.0
407
- prob_hash[14].should be_within(1e-10).of 13/400.0
408
- prob_hash[15].should be_within(1e-10).of 11/400.0
409
- prob_hash[16].should be_within(1e-10).of 9/400.0
410
- prob_hash[17].should be_within(1e-10).of 7/400.0
411
- prob_hash[18].should be_within(1e-10).of 5/400.0
412
- prob_hash[19].should be_within(1e-10).of 3/400.0
413
- prob_hash[20].should be_within(1e-10).of 1/400.0
414
- prob_hash.values.inject(:+).should be_within(1e-9).of 1.0
415
- end
416
- end
417
-
418
- end
419
-
420
- 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