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.
- checksums.yaml +7 -0
- data/.rubocop.yml +15 -0
- data/.travis.yml +9 -12
- data/CHANGELOG.md +29 -13
- data/Gemfile +2 -0
- data/README.md +5 -5
- data/Rakefile +14 -11
- data/ext/games_dice/extconf.rb +4 -22
- data/ext/games_dice/probabilities.c +1 -1
- data/games_dice.gemspec +26 -28
- data/lib/games_dice/bunch.rb +241 -247
- data/lib/games_dice/complex_die.rb +287 -303
- data/lib/games_dice/complex_die_helpers.rb +68 -0
- data/lib/games_dice/constants.rb +10 -10
- data/lib/games_dice/dice.rb +146 -143
- data/lib/games_dice/die.rb +101 -97
- data/lib/games_dice/die_result.rb +193 -189
- data/lib/games_dice/map_rule.rb +72 -70
- data/lib/games_dice/marshal.rb +18 -13
- data/lib/games_dice/parser.rb +219 -218
- data/lib/games_dice/reroll_rule.rb +76 -77
- data/lib/games_dice/version.rb +3 -1
- data/lib/games_dice.rb +19 -16
- data/spec/bunch_spec.rb +399 -421
- data/spec/complex_die_spec.rb +314 -306
- data/spec/dice_spec.rb +33 -34
- data/spec/die_result_spec.rb +163 -170
- data/spec/die_spec.rb +81 -82
- data/spec/helpers.rb +26 -22
- data/spec/map_rule_spec.rb +40 -44
- data/spec/parser_spec.rb +106 -82
- data/spec/probability_spec.rb +530 -527
- data/spec/readme_spec.rb +404 -384
- data/spec/reroll_rule_spec.rb +40 -44
- metadata +63 -74
- data/lib/games_dice/probabilities.rb +0 -445
data/spec/readme_spec.rb
CHANGED
@@ -1,384 +1,404 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
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.
|
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.
|
16
|
-
d = GamesDice.create '2d4-1'
|
17
|
-
d.
|
18
|
-
end
|
19
|
-
|
20
|
-
it "takes an optional parameter 'prng', which
|
21
|
-
prng = TestPRNG.new
|
22
|
-
|
23
|
-
d
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
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
|