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/readme_spec.rb CHANGED
@@ -1,384 +1,404 @@
1
- require 'games_dice'
2
- require 'helpers'
3
- # This spec demonstrates that documentation from the README.md works as intended
4
-
5
- describe GamesDice do
6
-
7
- describe '#create' do
8
- it "converts a string such as '3d6+6' into a GamesDice::Dice object" do
9
- d = GamesDice.create '3d6+6'
10
- d.is_a?( GamesDice::Dice ).should be_true
11
- end
12
-
13
- it "takes a parameter 'dice_description', which is a string such as '3d6' or '2d4-1'" do
14
- d = GamesDice.create '3d6'
15
- d.is_a?( GamesDice::Dice ).should be_true
16
- d = GamesDice.create '2d4-1'
17
- d.is_a?( GamesDice::Dice ).should be_true
18
- end
19
-
20
- it "takes an optional parameter 'prng', which if provided it should be an object that has a method 'rand( integer )'" do
21
- prng = TestPRNG.new
22
- d = GamesDice.create '3d6', prng
23
- d.is_a?( GamesDice::Dice ).should be_true
24
- end
25
- end # describe '#create'
26
-
27
- end # describe GamesDice
28
-
29
- describe GamesDice::Dice do
30
-
31
- before :each do
32
- srand(67809)
33
- end
34
-
35
- let(:dice) { GamesDice.create '3d6'}
36
-
37
- describe "#roll" do
38
- it "simulates rolling the dice as they were described in the constructor" do
39
- expected_results = [11,15,11,12,12,9]
40
- expected_results.each do |expected|
41
- dice.roll.should == expected
42
- end
43
- end
44
- end
45
-
46
- describe "#result" do
47
- it "returns the value from the last call to roll" do
48
- expected_results = [11,15,11,12,12,9]
49
- expected_results.each do |expected|
50
- dice.roll
51
- dice.result.should == expected
52
- end
53
- end
54
-
55
- it "will be nil if no roll has been made yet" do
56
- dice.result.should be_nil
57
- end
58
- end
59
-
60
- describe "#explain_result" do
61
- it "attempts to show how the result from the last call to roll was composed" do
62
- expected_results = [
63
- "3d6: 3 + 6 + 2 = 11",
64
- "3d6: 4 + 5 + 6 = 15",
65
- "3d6: 3 + 6 + 2 = 11",
66
- "3d6: 5 + 6 + 1 = 12"
67
- ]
68
- expected_results.each do |expected|
69
- dice.roll
70
- dice.explain_result.should == expected
71
- end
72
- end
73
-
74
- it "will be nil if no roll has been made yet" do
75
- dice.explain_result.should be_nil
76
- end
77
- end
78
-
79
- describe "#max" do
80
- it "returns the maximum possible value from a roll of the dice" do
81
- dice.max.should == 18
82
- end
83
- end
84
-
85
- describe "#min" do
86
- it "returns the minimum possible value from a roll of the dice" do
87
- dice.min.should == 3
88
- end
89
- end
90
-
91
- describe "#minmax" do
92
- it "returns an array [ dice.min, dice.max ]" do
93
- dice.minmax.should == [3,18]
94
- end
95
- end
96
-
97
- describe "#probabilities" do
98
- it "calculates probability distribution for the dice" do
99
- pd = dice.probabilities
100
- pd.is_a?( GamesDice::Probabilities ).should be_true
101
- pd.p_eql( 3).should be_within(1e-10).of 1.0/216
102
- pd.p_eql( 11 ).should be_within(1e-10).of 27.0/216
103
- end
104
- end
105
-
106
- end # describe GamesDice::Dice
107
-
108
- describe GamesDice::Probabilities do
109
- let(:probs) { GamesDice.create('3d6').probabilities }
110
-
111
- describe "#to_h" do
112
- it "returns a hash representation of the probability distribution" do
113
- h = probs.to_h
114
- h.should be_valid_distribution
115
- h[3].should be_within(1e-10).of 1.0/216
116
- h[11].should be_within(1e-10).of 27.0/216
117
- end
118
- end
119
-
120
- describe "#max" do
121
- it "returns maximum result in the probability distribution" do
122
- probs.max.should == 18
123
- end
124
- end
125
-
126
- describe "#min" do
127
- it "returns minimum result in the probability distribution" do
128
- probs.min.should == 3
129
- end
130
- end
131
-
132
- describe "#p_eql( n )" do
133
- it "returns the probability of a result equal to the integer n" do
134
- probs.p_eql( 3 ).should be_within(1e-10).of 1.0/216
135
- probs.p_eql( 2 ).should == 0.0
136
- end
137
- end
138
-
139
- describe "#p_gt( n )" do
140
- it "returns the probability of a result greater than the integer n" do
141
- probs.p_gt( 17 ).should be_within(1e-10).of 1.0/216
142
- probs.p_gt( 2 ).should == 1.0
143
- end
144
- end
145
-
146
- describe "#p_ge( n )" do
147
- it "returns the probability of a result greater than the integer n" do
148
- probs.p_ge( 17 ).should be_within(1e-10).of 4.0/216
149
- probs.p_ge( 3 ).should == 1.0
150
- end
151
- end
152
-
153
- describe "#p_le( n )" do
154
- it "returns the probability of a result less than or equal to the integer n" do
155
- probs.p_le( 17 ).should be_within(1e-10).of 215.0/216
156
- probs.p_le( 3 ).should be_within(1e-10).of 1.0/216
157
- end
158
- end
159
-
160
- describe "#p_lt( n )" do
161
- it "returns the probability of a result less than the integer n" do
162
- probs.p_lt( 17 ).should be_within(1e-10).of 212.0/216
163
- probs.p_lt( 3 ).should == 0.0
164
- end
165
- end
166
-
167
- end # describe GamesDice::Probabilities
168
-
169
- describe 'String Dice Description' do
170
-
171
- before :each do
172
- srand(35241)
173
- end
174
-
175
- describe "'1d6'" do
176
- it "returns expected results from rolling" do
177
- d = GamesDice.create '1d6'
178
- (1..20).map { |n| d.roll }.should == [6, 3, 2, 3, 4, 6, 4, 2, 6, 3, 3, 5, 6, 6, 3, 6, 5, 2, 1, 4]
179
- end
180
- end
181
-
182
- describe "'2d6 + 1d4'" do
183
- it "returns expected results from rolling" do
184
- d = GamesDice.create '2d6 + 1d4'
185
- (1..5).map { |n| d.roll }.should == [11, 10, 12, 12, 14]
186
- end
187
- end
188
-
189
- describe "'1d100 + 1d20 - 5'" do
190
- it "returns expected results from rolling" do
191
- d = GamesDice.create '1d100 + 1d20 - 5'
192
- (1..5).map { |n| d.roll }.should == [75, 78, 24, 102, 32]
193
- end
194
- end
195
-
196
- describe "'1d10x'" do
197
- it "returns expected results from rolling" do
198
- d = GamesDice.create '1d10x'
199
- (1..20).map { |n| d.roll }.should == [2, 3, 4, 7, 6, 7, 4, 2, 6, 3, 7, 5, 6, 7, 6, 6, 5, 19, 4, 19]
200
- end
201
- end
202
-
203
- describe "'1d6r1'" do
204
- it "returns expected results from rolling" do
205
- d = GamesDice.create '1d6r1'
206
- (1..20).map { |n| d.roll }.should == [6, 3, 2, 3, 4, 6, 4, 2, 6, 3, 3, 5, 6, 6, 3, 6, 5, 2, 4, 2]
207
- end
208
- end
209
-
210
- describe "'5d10r:10,add.k2'" do
211
- it "returns expected results from rolling" do
212
- d = GamesDice.create '5d10r:10,add.k2'
213
- (1..5).map { |n| d.roll }.should == [13, 13, 14, 38, 15]
214
- end
215
- end
216
-
217
- describe "'3d10m6'" do
218
- it "returns expected results from rolling" do
219
- d = GamesDice.create '3d10m6'
220
- (1..6).map { |n| d.roll }.should == [0, 3, 1, 1, 3, 2]
221
- end
222
- end
223
-
224
- describe "'5d10k2'" do
225
- it "returns expected results from rolling" do
226
- d = GamesDice.create '5d10k2'
227
- (1..5).map { |n| d.roll }.should == [13, 13, 14, 19, 19]
228
- end
229
- end
230
-
231
- describe "'5d10x'" do
232
- it "is the same as '5d10r:10,add.'" do
233
- srand(235241)
234
- d = GamesDice.create '5d10x'
235
- results1 = (1..50).map { d.roll }
236
-
237
- srand(235241)
238
- d = GamesDice.create '5d10r:10,add.'
239
- results2 = (1..50).map { d.roll }
240
-
241
- results1.should == results2
242
- end
243
- end
244
-
245
- describe "'1d6r:1.'" do
246
- it "should return same as '1d6r1'" do
247
- srand(235241)
248
- d = GamesDice.create '1d6r:1.'
249
- results1 = (1..50).map { d.roll }
250
-
251
- srand(235241)
252
- d = GamesDice.create '1d6r1'
253
- results2 = (1..50).map { d.roll }
254
-
255
- results1.should == results2
256
- end
257
- end
258
-
259
- describe "'1d10r:10,replace,1.'" do
260
- it "should roll a 10-sided die, re-roll a result of 10 and take the value of the second roll" do
261
- d = GamesDice.create '1d10r:10,replace,1.'
262
- (1..27).map { d.roll }.should == [2, 3, 4, 7, 6, 7, 4, 2, 6, 3, 7, 5, 6, 7, 6, 6, 5, 9, 4, 9, 8, 3, 1, 6, 7, 1, 1]
263
- end
264
- end
265
-
266
- describe "'1d20r:<=10,use_best,1.'" do
267
- it "should roll a 20-sided die, re-roll a result if 10 or lower, and use best result" do
268
- d = GamesDice.create '1d20r:<=10,use_best,1.'
269
- (1..20).map { d.roll }.should == [ 18, 19, 20, 20, 3, 11, 7, 20, 15, 19, 6, 16, 17, 16, 15, 11, 9, 15, 20, 16 ]
270
- end
271
- end
272
-
273
- describe "'5d10r:10,add.k2', '5d10xk2' and '5d10x.k2'" do
274
- it "should all be equivalent" do
275
- srand(135241)
276
- d = GamesDice.create '5d10r:10,add.k2'
277
- results1 = (1..50).map { d.roll }
278
-
279
- srand(135241)
280
- d = GamesDice.create '5d10xk2'
281
- results2 = (1..50).map { d.roll }
282
-
283
- srand(135241)
284
- d = GamesDice.create '5d10x.k2'
285
- results3 = (1..50).map { d.roll }
286
-
287
- results1.should == results2
288
- results2.should == results3
289
- end
290
- end
291
-
292
- describe "'5d10r:>8,add.'" do
293
- it "returns expected results from rolling" do
294
- d = GamesDice.create '5d10r:>8,add.'
295
- (1..5).map { |n| d.roll }.should == [22, 22, 31, 64, 26]
296
- end
297
- end
298
-
299
- describe "'9d6x.m:10.'" do
300
- it "returns expected results from rolling" do
301
- d = GamesDice.create '9d6x.m:10.'
302
- (1..5).map { |n| d.roll }.should == [1, 2, 1, 1, 1]
303
- end
304
- it "can be explained as number of exploding dice scoring 10+" do
305
- d = GamesDice.create '9d6x.m:10.'
306
- (1..5).map { |n| d.roll; d.explain_result }.should == [
307
- "9d6: [6+3] 9, 2, 3, 4, [6+4] 10, 2, [6+3] 9, 3, 5. Successes: 1",
308
- "9d6: [6+6+3] 15, [6+5] 11, 2, 1, 4, 2, 1, 3, 5. Successes: 2",
309
- "9d6: 1, [6+6+1] 13, 2, 1, 1, 3, [6+1] 7, 5, 4. Successes: 1",
310
- "9d6: [6+4] 10, 3, 4, 5, 5, 1, [6+3] 9, 3, 5. Successes: 1",
311
- "9d6: [6+3] 9, 3, [6+5] 11, 4, 2, 2, 1, 4, 5. Successes: 1"
312
- ]
313
- end
314
- end
315
-
316
- describe "'9d6x.m:10,1,S.'" do
317
- it "returns expected results from rolling" do
318
- d = GamesDice.create '9d6x.m:10,1,S.'
319
- (1..5).map { |n| d.roll }.should == [1, 2, 1, 1, 1]
320
- end
321
- it "includes the string 'S' next to each success" do
322
- d = GamesDice.create '9d6x.m:10,1,S.'
323
- (1..5).map { |n| d.roll; d.explain_result }.should == [
324
- "9d6: [6+3] 9, 2, 3, 4, [6+4] 10 S, 2, [6+3] 9, 3, 5. Successes: 1",
325
- "9d6: [6+6+3] 15 S, [6+5] 11 S, 2, 1, 4, 2, 1, 3, 5. Successes: 2",
326
- "9d6: 1, [6+6+1] 13 S, 2, 1, 1, 3, [6+1] 7, 5, 4. Successes: 1",
327
- "9d6: [6+4] 10 S, 3, 4, 5, 5, 1, [6+3] 9, 3, 5. Successes: 1",
328
- "9d6: [6+3] 9, 3, [6+5] 11 S, 4, 2, 2, 1, 4, 5. Successes: 1"
329
- ]
330
- end
331
- end
332
-
333
- describe "'5d10m:>=6,1,S.m:==1,-1,F.'" do
334
- it "returns expected results from rolling" do
335
- d = GamesDice.create '5d10m:>=6,1,S.m:==1,-1,F.'
336
- (1..10).map { |n| d.roll }.should == [2, 2, 4, 3, 2, 1, 1, 3, 3, 0]
337
- end
338
- it "includes the string 'S' next to each success, and 'F' next to each 'fumble'" do
339
- d = GamesDice.create '5d10m:>=6,1,S.m:==1,-1,F.'
340
- (1..5).map { |n| d.roll; d.explain_result }.should == [
341
- "5d10: 2, 3, 4, 7 S, 6 S. Successes: 2",
342
- "5d10: 7 S, 4, 2, 6 S, 3. Successes: 2",
343
- "5d10: 7 S, 5, 6 S, 7 S, 6 S. Successes: 4",
344
- "5d10: 6 S, 5, 10 S, 9 S, 4. Successes: 3",
345
- "5d10: 10 S, 9 S, 8 S, 3, 1 F. Successes: 2"
346
- ]
347
- end
348
- end
349
-
350
- describe "'4d6k:3.r:1,replace,1.'" do
351
- it "represents roll 4 six-sided dice, re-roll any 1s, and keep best 3." do
352
- d = GamesDice.create '4d6k:3.r:1,replace,1.'
353
- (1..10).map { |n| d.roll }.should == [12, 14, 14, 18, 11, 17, 11, 15, 14, 14]
354
- end
355
- it "includes re-rolls and keeper choice in explanations" do
356
- d = GamesDice.create '4d6k:3.r:1,replace,1.'
357
- (1..5).map { |n| d.roll; d.explain_result }.should == [
358
- "4d6: 6, 3, 2, 3. Keep: 3 + 3 + 6 = 12",
359
- "4d6: 4, 6, 4, 2. Keep: 4 + 4 + 6 = 14",
360
- "4d6: 6, 3, 3, 5. Keep: 3 + 5 + 6 = 14",
361
- "4d6: 6, 6, 3, 6. Keep: 6 + 6 + 6 = 18",
362
- "4d6: 5, 2, [1|4] 4, 2. Keep: 2 + 4 + 5 = 11"
363
- ]
364
- end
365
- end
366
-
367
- describe "'2d20k:1,worst.'" do
368
- it "represents roll 2 twenty-sided dice, return lowest of the two results" do
369
- d = GamesDice.create '2d20k:1,worst.'
370
- (1..10).map { |n| d.roll }.should == [18, 6, 2, 3, 5, 10, 15, 1, 7, 10]
371
- end
372
- it "includes keeper choice in explanations" do
373
- d = GamesDice.create '2d20k:1,worst.'
374
- (1..5).map { |n| d.roll; d.explain_result }.should == [
375
- "2d20: 18, 19. Keep: 18",
376
- "2d20: 20, 6. Keep: 6",
377
- "2d20: 20, 2. Keep: 2",
378
- "2d20: 3, 11. Keep: 3",
379
- "2d20: 5, 7. Keep: 5"
380
- ]
381
- end
382
- end
383
-
384
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'helpers'
4
+ # This spec demonstrates that documentation from the README.md works as intended
5
+
6
+ describe GamesDice do
7
+ describe '#create' do
8
+ it "converts a string such as '3d6+6' into a GamesDice::Dice object" do
9
+ d = GamesDice.create '3d6+6'
10
+ expect(d).to be_a GamesDice::Dice
11
+ end
12
+
13
+ it "takes a parameter 'dice_description', which is a string such as '3d6' or '2d4-1'" do
14
+ d = GamesDice.create '3d6'
15
+ expect(d).to be_a GamesDice::Dice
16
+ d = GamesDice.create '2d4-1'
17
+ expect(d).to be_a GamesDice::Dice
18
+ end
19
+
20
+ it "takes an optional parameter 'prng', which should be an object that has a method 'rand( integer )'" do
21
+ prng = TestPRNG.new
22
+
23
+ d = GamesDice.create '3d6', prng
24
+ expect(d).to be_a GamesDice::Dice
25
+
26
+ (0..5).each do |dresult|
27
+ allow(prng).to receive(:rand).and_return(dresult)
28
+ expect(prng).to receive(:rand).with(6)
29
+ expect(d.roll).to eql (dresult + 1) * 3
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ describe GamesDice::Dice do
36
+ before :each do
37
+ srand(67_809)
38
+ end
39
+
40
+ let(:dice) { GamesDice.create '3d6' }
41
+
42
+ describe '#roll' do
43
+ it 'simulates rolling the dice as they were described in the constructor' do
44
+ expected_results = [11, 15, 11, 12, 12, 9]
45
+ expected_results.each do |expected|
46
+ expect(dice.roll).to eql expected
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#result' do
52
+ it 'returns the value from the last call to roll' do
53
+ expected_results = [11, 15, 11, 12, 12, 9]
54
+ expected_results.each do |expected|
55
+ dice.roll
56
+ expect(dice.result).to eql expected
57
+ end
58
+ end
59
+
60
+ it 'will be nil if no roll has been made yet' do
61
+ expect(dice.result).to be_nil
62
+ end
63
+ end
64
+
65
+ describe '#explain_result' do
66
+ it 'attempts to show how the result from the last call to roll was composed' do
67
+ expected_results = [
68
+ '3d6: 3 + 6 + 2 = 11',
69
+ '3d6: 4 + 5 + 6 = 15',
70
+ '3d6: 3 + 6 + 2 = 11',
71
+ '3d6: 5 + 6 + 1 = 12'
72
+ ]
73
+ expected_results.each do |expected|
74
+ dice.roll
75
+ expect(dice.explain_result).to eql expected
76
+ end
77
+ end
78
+
79
+ it 'will be nil if no roll has been made yet' do
80
+ expect(dice.explain_result).to be_nil
81
+ end
82
+ end
83
+
84
+ describe '#max' do
85
+ it 'returns the maximum possible value from a roll of the dice' do
86
+ expect(dice.max).to eql 18
87
+ end
88
+ end
89
+
90
+ describe '#min' do
91
+ it 'returns the minimum possible value from a roll of the dice' do
92
+ expect(dice.min).to eql 3
93
+ end
94
+ end
95
+
96
+ describe '#minmax' do
97
+ it 'returns an array [ dice.min, dice.max ]' do
98
+ expect(dice.minmax).to eql [3, 18]
99
+ end
100
+ end
101
+
102
+ describe '#probabilities' do
103
+ it 'calculates probability distribution for the dice' do
104
+ pd = dice.probabilities
105
+ expect(pd).to be_a GamesDice::Probabilities
106
+ expect(pd.p_eql(3)).to be_within(1e-10).of 1.0 / 216
107
+ expect(pd.p_eql(11)).to be_within(1e-10).of 27.0 / 216
108
+ end
109
+ end
110
+ end
111
+
112
+ describe GamesDice::Probabilities do
113
+ let(:probs) { GamesDice.create('3d6').probabilities }
114
+
115
+ describe '#to_h' do
116
+ it 'returns a hash representation of the probability distribution' do
117
+ h = probs.to_h
118
+ expect(h).to be_valid_distribution
119
+ expect(h[3]).to be_within(1e-10).of 1.0 / 216
120
+ expect(h[11]).to be_within(1e-10).of 27.0 / 216
121
+ end
122
+ end
123
+
124
+ describe '#max' do
125
+ it 'returns maximum result in the probability distribution' do
126
+ expect(probs.max).to eql 18
127
+ end
128
+ end
129
+
130
+ describe '#min' do
131
+ it 'returns minimum result in the probability distribution' do
132
+ expect(probs.min).to eql 3
133
+ end
134
+ end
135
+
136
+ describe '#p_eql( n )' do
137
+ it 'returns the probability of a result equal to the integer n' do
138
+ expect(probs.p_eql(3)).to be_within(1e-10).of 1.0 / 216
139
+ expect(probs.p_eql(2)).to eql 0.0
140
+ end
141
+ end
142
+
143
+ describe '#p_gt( n )' do
144
+ it 'returns the probability of a result greater than the integer n' do
145
+ expect(probs.p_gt(17)).to be_within(1e-10).of 1.0 / 216
146
+ expect(probs.p_gt(2)).to eql 1.0
147
+ end
148
+ end
149
+
150
+ describe '#p_ge( n )' do
151
+ it 'returns the probability of a result greater than the integer n' do
152
+ expect(probs.p_ge(17)).to be_within(1e-10).of 4.0 / 216
153
+ expect(probs.p_ge(3)).to eql 1.0
154
+ end
155
+ end
156
+
157
+ describe '#p_le( n )' do
158
+ it 'returns the probability of a result less than or equal to the integer n' do
159
+ expect(probs.p_le(17)).to be_within(1e-10).of 215.0 / 216
160
+ expect(probs.p_le(3)).to be_within(1e-10).of 1.0 / 216
161
+ end
162
+ end
163
+
164
+ describe '#p_lt( n )' do
165
+ it 'returns the probability of a result less than the integer n' do
166
+ expect(probs.p_lt(17)).to be_within(1e-10).of 212.0 / 216
167
+ expect(probs.p_lt(3)).to eql 0.0
168
+ end
169
+ end
170
+ end
171
+
172
+ describe 'String Dice Description' do
173
+ before :each do
174
+ srand(35_241)
175
+ end
176
+
177
+ describe "'1d6'" do
178
+ it 'returns expected results from rolling' do
179
+ d = GamesDice.create '1d6'
180
+ expect((1..20).map { |_n| d.roll }).to eql [6, 3, 2, 3, 4, 6, 4, 2, 6, 3, 3, 5, 6, 6, 3, 6, 5, 2, 1, 4]
181
+ end
182
+ end
183
+
184
+ describe "'2d6 + 1d4'" do
185
+ it 'returns expected results from rolling' do
186
+ d = GamesDice.create '2d6 + 1d4'
187
+ expect((1..5).map { |_n| d.roll }).to eql [11, 10, 12, 12, 14]
188
+ end
189
+ end
190
+
191
+ describe "'1d100 + 1d20 - 5'" do
192
+ it 'returns expected results from rolling' do
193
+ d = GamesDice.create '1d100 + 1d20 - 5'
194
+ expect((1..5).map { |_n| d.roll }).to eql [75, 78, 24, 102, 32]
195
+ end
196
+ end
197
+
198
+ describe "'1d10x'" do
199
+ it 'returns expected results from rolling' do
200
+ d = GamesDice.create '1d10x'
201
+ expect((1..20).map { |_n| d.roll }).to eql [2, 3, 4, 7, 6, 7, 4, 2, 6, 3, 7, 5, 6, 7, 6, 6, 5, 19, 4, 19]
202
+ end
203
+ end
204
+
205
+ describe "'1d6r1'" do
206
+ it 'returns expected results from rolling' do
207
+ d = GamesDice.create '1d6r1'
208
+ expect((1..20).map { |_n| d.roll }).to eql [6, 3, 2, 3, 4, 6, 4, 2, 6, 3, 3, 5, 6, 6, 3, 6, 5, 2, 4, 2]
209
+ end
210
+ end
211
+
212
+ describe "'5d10r:10,add.k2'" do
213
+ it 'returns expected results from rolling' do
214
+ d = GamesDice.create '5d10r:10,add.k2'
215
+ expect((1..5).map { |_n| d.roll }).to eql [13, 13, 14, 38, 15]
216
+ end
217
+ end
218
+
219
+ describe "'3d10m6'" do
220
+ it 'returns expected results from rolling' do
221
+ d = GamesDice.create '3d10m6'
222
+ expect((1..6).map { |_n| d.roll }).to eql [0, 3, 1, 1, 3, 2]
223
+ end
224
+ end
225
+
226
+ describe "'5d10k2'" do
227
+ it 'returns expected results from rolling' do
228
+ d = GamesDice.create '5d10k2'
229
+ expect((1..5).map { |_n| d.roll }).to eql [13, 13, 14, 19, 19]
230
+ end
231
+ end
232
+
233
+ describe "'5d10x'" do
234
+ it "is the same as '5d10r:10,add.'" do
235
+ srand(235_241)
236
+ d = GamesDice.create '5d10x'
237
+ results1 = (1..50).map { d.roll }
238
+
239
+ srand(235_241)
240
+ d = GamesDice.create '5d10r:10,add.'
241
+ results2 = (1..50).map { d.roll }
242
+
243
+ expect(results1).to eql results2
244
+ end
245
+ end
246
+
247
+ describe "'1d6r:1.'" do
248
+ it "should return same as '1d6r1'" do
249
+ srand(235_241)
250
+ d = GamesDice.create '1d6r:1.'
251
+ results1 = (1..50).map { d.roll }
252
+
253
+ srand(235_241)
254
+ d = GamesDice.create '1d6r1'
255
+ results2 = (1..50).map { d.roll }
256
+
257
+ expect(results1).to eql results2
258
+ end
259
+ end
260
+
261
+ describe "'1d10r:10,replace,1.'" do
262
+ it 'should roll a 10-sided die, re-roll a result of 10 and take the value of the second roll' do
263
+ d = GamesDice.create '1d10r:10,replace,1.'
264
+ expect((1..27).map do
265
+ d.roll
266
+ end).to eql [2, 3, 4, 7, 6, 7, 4, 2, 6, 3, 7, 5, 6, 7, 6, 6, 5, 9, 4, 9, 8, 3, 1, 6, 7, 1, 1]
267
+ end
268
+ end
269
+
270
+ describe "'1d20r:<=10,use_best,1.'" do
271
+ it 'should roll a 20-sided die, re-roll a result if 10 or lower, and use best result' do
272
+ d = GamesDice.create '1d20r:<=10,use_best,1.'
273
+ expect((1..20).map do
274
+ d.roll
275
+ end).to eql [18, 19, 20, 20, 3, 11, 7, 20, 15, 19, 6, 16, 17, 16, 15, 11, 9, 15, 20, 16]
276
+ end
277
+ end
278
+
279
+ describe "'5d10r:10,add.k2', '5d10xk2' and '5d10x.k2'" do
280
+ it 'should all be equivalent' do
281
+ srand(135_241)
282
+ d = GamesDice.create '5d10r:10,add.k2'
283
+ results1 = (1..50).map { d.roll }
284
+
285
+ srand(135_241)
286
+ d = GamesDice.create '5d10xk2'
287
+ results2 = (1..50).map { d.roll }
288
+
289
+ srand(135_241)
290
+ d = GamesDice.create '5d10x.k2'
291
+ results3 = (1..50).map { d.roll }
292
+
293
+ expect(results1).to eql results2
294
+ expect(results1).to eql results3
295
+ end
296
+ end
297
+
298
+ describe "'5d10r:>8,add.'" do
299
+ it 'returns expected results from rolling' do
300
+ d = GamesDice.create '5d10r:>8,add.'
301
+ expect((1..5).map { |_n| d.roll }).to eql [22, 22, 31, 64, 26]
302
+ end
303
+ end
304
+
305
+ describe "'9d6x.m:10.'" do
306
+ it 'returns expected results from rolling' do
307
+ d = GamesDice.create '9d6x.m:10.'
308
+ expect((1..5).map { |_n| d.roll }).to eql [1, 2, 1, 1, 1]
309
+ end
310
+ it 'can be explained as number of exploding dice scoring 10+' do
311
+ d = GamesDice.create '9d6x.m:10.'
312
+ expect((1..5).map do |_n|
313
+ d.roll
314
+ d.explain_result
315
+ end).to eql [
316
+ '9d6: [6+3] 9, 2, 3, 4, [6+4] 10, 2, [6+3] 9, 3, 5. Successes: 1',
317
+ '9d6: [6+6+3] 15, [6+5] 11, 2, 1, 4, 2, 1, 3, 5. Successes: 2',
318
+ '9d6: 1, [6+6+1] 13, 2, 1, 1, 3, [6+1] 7, 5, 4. Successes: 1',
319
+ '9d6: [6+4] 10, 3, 4, 5, 5, 1, [6+3] 9, 3, 5. Successes: 1',
320
+ '9d6: [6+3] 9, 3, [6+5] 11, 4, 2, 2, 1, 4, 5. Successes: 1'
321
+ ]
322
+ end
323
+ end
324
+
325
+ describe "'9d6x.m:10,1,S.'" do
326
+ it 'returns expected results from rolling' do
327
+ d = GamesDice.create '9d6x.m:10,1,S.'
328
+ expect((1..5).map { |_n| d.roll }).to eql [1, 2, 1, 1, 1]
329
+ end
330
+ it "includes the string 'S' next to each success" do
331
+ d = GamesDice.create '9d6x.m:10,1,S.'
332
+ expect((1..5).map do |_n|
333
+ d.roll
334
+ d.explain_result
335
+ end).to eql [
336
+ '9d6: [6+3] 9, 2, 3, 4, [6+4] 10 S, 2, [6+3] 9, 3, 5. Successes: 1',
337
+ '9d6: [6+6+3] 15 S, [6+5] 11 S, 2, 1, 4, 2, 1, 3, 5. Successes: 2',
338
+ '9d6: 1, [6+6+1] 13 S, 2, 1, 1, 3, [6+1] 7, 5, 4. Successes: 1',
339
+ '9d6: [6+4] 10 S, 3, 4, 5, 5, 1, [6+3] 9, 3, 5. Successes: 1',
340
+ '9d6: [6+3] 9, 3, [6+5] 11 S, 4, 2, 2, 1, 4, 5. Successes: 1'
341
+ ]
342
+ end
343
+ end
344
+
345
+ describe "'5d10m:>=6,1,S.m:==1,-1,F.'" do
346
+ it 'returns expected results from rolling' do
347
+ d = GamesDice.create '5d10m:>=6,1,S.m:==1,-1,F.'
348
+ expect((1..10).map { |_n| d.roll }).to eql [2, 2, 4, 3, 2, 1, 1, 3, 3, 0]
349
+ end
350
+ it "includes the string 'S' next to each success, and 'F' next to each 'fumble'" do
351
+ d = GamesDice.create '5d10m:>=6,1,S.m:==1,-1,F.'
352
+ expect((1..5).map do |_n|
353
+ d.roll
354
+ d.explain_result
355
+ end).to eql [
356
+ '5d10: 2, 3, 4, 7 S, 6 S. Successes: 2',
357
+ '5d10: 7 S, 4, 2, 6 S, 3. Successes: 2',
358
+ '5d10: 7 S, 5, 6 S, 7 S, 6 S. Successes: 4',
359
+ '5d10: 6 S, 5, 10 S, 9 S, 4. Successes: 3',
360
+ '5d10: 10 S, 9 S, 8 S, 3, 1 F. Successes: 2'
361
+ ]
362
+ end
363
+ end
364
+
365
+ describe "'4d6k:3.r:1,replace,1.'" do
366
+ it 'represents roll 4 six-sided dice, re-roll any 1s, and keep best 3.' do
367
+ d = GamesDice.create '4d6k:3.r:1,replace,1.'
368
+ expect((1..10).map { |_n| d.roll }).to eql [12, 14, 14, 18, 11, 17, 11, 15, 14, 14]
369
+ end
370
+ it 'includes re-rolls and keeper choice in explanations' do
371
+ d = GamesDice.create '4d6k:3.r:1,replace,1.'
372
+ expect((1..5).map do |_n|
373
+ d.roll
374
+ d.explain_result
375
+ end).to eql [
376
+ '4d6: 6, 3, 2, 3. Keep: 3 + 3 + 6 = 12',
377
+ '4d6: 4, 6, 4, 2. Keep: 4 + 4 + 6 = 14',
378
+ '4d6: 6, 3, 3, 5. Keep: 3 + 5 + 6 = 14',
379
+ '4d6: 6, 6, 3, 6. Keep: 6 + 6 + 6 = 18',
380
+ '4d6: 5, 2, [1|4] 4, 2. Keep: 2 + 4 + 5 = 11'
381
+ ]
382
+ end
383
+ end
384
+
385
+ describe "'2d20k:1,worst.'" do
386
+ it 'represents roll 2 twenty-sided dice, return lowest of the two results' do
387
+ d = GamesDice.create '2d20k:1,worst.'
388
+ expect((1..10).map { |_n| d.roll }).to eql [18, 6, 2, 3, 5, 10, 15, 1, 7, 10]
389
+ end
390
+ it 'includes keeper choice in explanations' do
391
+ d = GamesDice.create '2d20k:1,worst.'
392
+ expect((1..5).map do |_n|
393
+ d.roll
394
+ d.explain_result
395
+ end).to eql [
396
+ '2d20: 18, 19. Keep: 18',
397
+ '2d20: 20, 6. Keep: 6',
398
+ '2d20: 20, 2. Keep: 2',
399
+ '2d20: 3, 11. Keep: 3',
400
+ '2d20: 5, 7. Keep: 5'
401
+ ]
402
+ end
403
+ end
404
+ end