games_dice 0.3.12 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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