games_dice 0.3.9 → 0.4.0

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