games_dice 0.3.12 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/spec/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