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