games_dice 0.4.0 → 0.4.2
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 +4 -4
- data/.github/workflows/ci.yml +38 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +41 -3
- data/.yardopts +1 -1
- data/CHANGELOG.md +12 -0
- data/Gemfile +10 -0
- data/README.md +11 -33
- data/Rakefile +2 -18
- data/ext/games_dice/games_dice.c +1 -1
- data/ext/games_dice/probabilities.c +127 -8
- data/ext/games_dice/probabilities.h +1 -1
- data/games_dice.gemspec +11 -19
- data/lib/games_dice/bunch.rb +27 -65
- data/lib/games_dice/bunch_helpers.rb +68 -0
- data/lib/games_dice/complex_die.rb +10 -146
- data/lib/games_dice/complex_die_helpers.rb +238 -46
- data/lib/games_dice/dice.rb +17 -10
- data/lib/games_dice/die.rb +2 -2
- data/lib/games_dice/die_result.rb +84 -71
- data/lib/games_dice/marshal.rb +26 -3
- data/lib/games_dice/parser.rb +128 -102
- data/lib/games_dice/version.rb +2 -1
- data/lib/games_dice.rb +7 -9
- data/spec/bunch_spec.rb +72 -72
- data/spec/complex_die_spec.rb +158 -158
- data/spec/dice_spec.rb +5 -5
- data/spec/die_result_spec.rb +98 -98
- data/spec/die_spec.rb +19 -19
- data/spec/helpers.rb +2 -4
- data/spec/map_rule_spec.rb +17 -17
- data/spec/parser_spec.rb +7 -7
- data/spec/probability_spec.rb +188 -196
- data/spec/readme_spec.rb +28 -22
- data/spec/reroll_rule_spec.rb +15 -15
- metadata +16 -139
- data/.travis.yml +0 -11
data/spec/die_result_spec.rb
CHANGED
|
@@ -4,157 +4,157 @@ require 'helpers'
|
|
|
4
4
|
|
|
5
5
|
describe GamesDice::DieResult do
|
|
6
6
|
describe '.new' do
|
|
7
|
-
it "
|
|
8
|
-
die_result =
|
|
9
|
-
expect(die_result.value).to
|
|
7
|
+
it "work without parameters to represent 'no results yet'" do
|
|
8
|
+
die_result = described_class.new
|
|
9
|
+
expect(die_result.value).to be_nil
|
|
10
10
|
expect(die_result.rolls).to eql []
|
|
11
11
|
expect(die_result.roll_reasons).to eql []
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
it '
|
|
15
|
-
die_result =
|
|
16
|
-
expect(die_result.value).to
|
|
14
|
+
it 'work with a single Integer param to represent an initial result' do
|
|
15
|
+
die_result = described_class.new(8)
|
|
16
|
+
expect(die_result.value).to be 8
|
|
17
17
|
expect(die_result.rolls).to eql [8]
|
|
18
18
|
expect(die_result.roll_reasons).to eql [:basic]
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
it '
|
|
22
|
-
expect
|
|
23
|
-
expect
|
|
21
|
+
it 'not accept a param that cannot be coerced to Integer' do
|
|
22
|
+
expect { described_class.new([]) }.to raise_error(TypeError)
|
|
23
|
+
expect { described_class.new('N') }.to raise_error(ArgumentError)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
it '
|
|
27
|
-
expect
|
|
28
|
-
expect
|
|
26
|
+
it 'not accept unknown reasons for making a roll' do
|
|
27
|
+
expect { described_class.new(8, 'wooo') }.to raise_error(ArgumentError)
|
|
28
|
+
expect { described_class.new(8, :frabulous) }.to raise_error(ArgumentError)
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
describe '#add_roll' do
|
|
33
|
-
context "starting from 'no results yet'" do
|
|
34
|
-
let(:die_result) {
|
|
33
|
+
context "when starting from 'no results yet'" do
|
|
34
|
+
let(:die_result) { described_class.new }
|
|
35
35
|
|
|
36
|
-
it '
|
|
36
|
+
it 'create an initial result' do
|
|
37
37
|
die_result.add_roll(5)
|
|
38
|
-
expect(die_result.value).to
|
|
38
|
+
expect(die_result.value).to be 5
|
|
39
39
|
expect(die_result.rolls).to eql [5]
|
|
40
40
|
expect(die_result.roll_reasons).to eql [:basic]
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
it '
|
|
43
|
+
it 'accept non-basic reasons for the first roll' do
|
|
44
44
|
die_result.add_roll(4, :reroll_subtract)
|
|
45
|
-
expect(die_result.value).to
|
|
45
|
+
expect(die_result.value).to be(-4)
|
|
46
46
|
expect(die_result.rolls).to eql [4]
|
|
47
47
|
expect(die_result.roll_reasons).to eql [:reroll_subtract]
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
it '
|
|
51
|
-
expect
|
|
52
|
-
expect
|
|
50
|
+
it 'not accept a first param that cannot be coerced to Integer' do
|
|
51
|
+
expect { die_result.add_roll([]) }.to raise_error(TypeError)
|
|
52
|
+
expect { die_result.add_roll('N') }.to raise_error(ArgumentError)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
it '
|
|
56
|
-
expect
|
|
57
|
-
expect
|
|
55
|
+
it 'not accept an unsupported second param' do
|
|
56
|
+
expect { die_result.add_roll(5, []) }.to raise_error(ArgumentError)
|
|
57
|
+
expect { die_result.add_roll(15, :bam) }.to raise_error(ArgumentError)
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
context 'starting with an initial result' do
|
|
62
|
-
let(:die_result) {
|
|
61
|
+
context 'when starting with an initial result' do
|
|
62
|
+
let(:die_result) { described_class.new(7) }
|
|
63
63
|
|
|
64
|
-
it '
|
|
65
|
-
expect
|
|
66
|
-
expect
|
|
64
|
+
it 'not accept a first param that cannot be coerced to Integer' do
|
|
65
|
+
expect { die_result.add_roll([]) }.to raise_error(TypeError)
|
|
66
|
+
expect { die_result.add_roll('N') }.to raise_error(ArgumentError)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
it '
|
|
70
|
-
expect
|
|
71
|
-
expect
|
|
69
|
+
it 'not accept an unsupported second param' do
|
|
70
|
+
expect { die_result.add_roll(5, []) }.to raise_error(ArgumentError)
|
|
71
|
+
expect { die_result.add_roll(15, :bam) }.to raise_error(ArgumentError)
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
context '
|
|
75
|
-
it '
|
|
74
|
+
context 'when adding another basic roll' do
|
|
75
|
+
it 'replace an initial result, as if the die were re-rolled' do
|
|
76
76
|
die_result.add_roll(5)
|
|
77
|
-
expect(die_result.value).to
|
|
77
|
+
expect(die_result.value).to be 5
|
|
78
78
|
expect(die_result.rolls).to eql [7, 5]
|
|
79
79
|
expect(die_result.roll_reasons).to eql %i[basic basic]
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
-
context 'exploding dice' do
|
|
84
|
-
it '
|
|
83
|
+
context 'with exploding dice' do
|
|
84
|
+
it 'add to value when exploding up' do
|
|
85
85
|
die_result.add_roll(6, :reroll_add)
|
|
86
|
-
expect(die_result.value).to
|
|
86
|
+
expect(die_result.value).to be 13
|
|
87
87
|
expect(die_result.rolls).to eql [7, 6]
|
|
88
88
|
expect(die_result.roll_reasons).to eql %i[basic reroll_add]
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
-
it '
|
|
91
|
+
it 'subtract from value when exploding down' do
|
|
92
92
|
die_result.add_roll(4, :reroll_subtract)
|
|
93
|
-
expect(die_result.value).to
|
|
93
|
+
expect(die_result.value).to be 3
|
|
94
94
|
expect(die_result.rolls).to eql [7, 4]
|
|
95
95
|
expect(die_result.roll_reasons).to eql %i[basic reroll_subtract]
|
|
96
96
|
end
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
-
context 're-roll dice' do
|
|
100
|
-
it '
|
|
99
|
+
context 'with re-roll dice' do
|
|
100
|
+
it 'optionally replace roll unconditionally' do
|
|
101
101
|
die_result.add_roll(2, :reroll_replace)
|
|
102
|
-
expect(die_result.value).to
|
|
102
|
+
expect(die_result.value).to be 2
|
|
103
103
|
expect(die_result.rolls).to eql [7, 2]
|
|
104
104
|
expect(die_result.roll_reasons).to eql %i[basic reroll_replace]
|
|
105
105
|
|
|
106
106
|
die_result.add_roll(5, :reroll_replace)
|
|
107
|
-
expect(die_result.value).to
|
|
107
|
+
expect(die_result.value).to be 5
|
|
108
108
|
expect(die_result.rolls).to eql [7, 2, 5]
|
|
109
109
|
expect(die_result.roll_reasons).to eql %i[basic reroll_replace reroll_replace]
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
-
it '
|
|
112
|
+
it 'optionally use best roll' do
|
|
113
113
|
die_result.add_roll(2, :reroll_use_best)
|
|
114
|
-
expect(die_result.value).to
|
|
114
|
+
expect(die_result.value).to be 7
|
|
115
115
|
expect(die_result.rolls).to eql [7, 2]
|
|
116
116
|
expect(die_result.roll_reasons).to eql %i[basic reroll_use_best]
|
|
117
117
|
|
|
118
118
|
die_result.add_roll(9, :reroll_use_best)
|
|
119
|
-
expect(die_result.value).to
|
|
119
|
+
expect(die_result.value).to be 9
|
|
120
120
|
expect(die_result.rolls).to eql [7, 2, 9]
|
|
121
121
|
expect(die_result.roll_reasons).to eql %i[basic reroll_use_best reroll_use_best]
|
|
122
122
|
end
|
|
123
123
|
|
|
124
|
-
it '
|
|
124
|
+
it 'optionally use worst roll' do
|
|
125
125
|
die_result.add_roll(4, :reroll_use_worst)
|
|
126
|
-
expect(die_result.value).to
|
|
126
|
+
expect(die_result.value).to be 4
|
|
127
127
|
expect(die_result.rolls).to eql [7, 4]
|
|
128
128
|
expect(die_result.roll_reasons).to eql %i[basic reroll_use_worst]
|
|
129
129
|
|
|
130
130
|
die_result.add_roll(5, :reroll_use_worst)
|
|
131
|
-
expect(die_result.value).to
|
|
131
|
+
expect(die_result.value).to be 4
|
|
132
132
|
expect(die_result.rolls).to eql [7, 4, 5]
|
|
133
133
|
expect(die_result.roll_reasons).to eql %i[basic reroll_use_worst reroll_use_worst]
|
|
134
134
|
end
|
|
135
135
|
end
|
|
136
136
|
|
|
137
|
-
context 'combinations of reroll reasons' do
|
|
138
|
-
it '
|
|
137
|
+
context 'with combinations of reroll reasons' do
|
|
138
|
+
it 'correctly handle valid reasons for extra rolls in combination' do
|
|
139
139
|
die_result.add_roll(10, :reroll_add)
|
|
140
140
|
die_result.add_roll(3, :reroll_subtract)
|
|
141
|
-
expect(die_result.value).to
|
|
141
|
+
expect(die_result.value).to be 14
|
|
142
142
|
expect(die_result.rolls).to eql [7, 10, 3]
|
|
143
143
|
expect(die_result.roll_reasons).to eql %i[basic reroll_add reroll_subtract]
|
|
144
144
|
|
|
145
145
|
die_result.add_roll(12, :reroll_replace)
|
|
146
|
-
expect(die_result.value).to
|
|
146
|
+
expect(die_result.value).to be 12
|
|
147
147
|
expect(die_result.rolls).to eql [7, 10, 3, 12]
|
|
148
148
|
expect(die_result.roll_reasons).to eql %i[basic reroll_add reroll_subtract reroll_replace]
|
|
149
149
|
|
|
150
150
|
die_result.add_roll(9, :reroll_use_best)
|
|
151
|
-
expect(die_result.value).to
|
|
151
|
+
expect(die_result.value).to be 12
|
|
152
152
|
expect(die_result.rolls).to eql [7, 10, 3, 12, 9]
|
|
153
153
|
expect(die_result.roll_reasons).to eql %i[basic reroll_add reroll_subtract reroll_replace
|
|
154
154
|
reroll_use_best]
|
|
155
155
|
|
|
156
156
|
die_result.add_roll(15, :reroll_add)
|
|
157
|
-
expect(die_result.value).to
|
|
157
|
+
expect(die_result.value).to be 27
|
|
158
158
|
expect(die_result.rolls).to eql [7, 10, 3, 12, 9, 15]
|
|
159
159
|
expect(die_result.roll_reasons).to eql %i[basic reroll_add reroll_subtract reroll_replace
|
|
160
160
|
reroll_use_best reroll_add]
|
|
@@ -164,18 +164,18 @@ describe GamesDice::DieResult do
|
|
|
164
164
|
end
|
|
165
165
|
|
|
166
166
|
describe '#explain_value' do
|
|
167
|
-
let(:die_result) {
|
|
167
|
+
let(:die_result) { described_class.new }
|
|
168
168
|
|
|
169
|
-
it "
|
|
169
|
+
it "be empty string for 'no results yet'" do
|
|
170
170
|
expect(die_result.explain_value).to eql ''
|
|
171
171
|
end
|
|
172
172
|
|
|
173
|
-
it '
|
|
173
|
+
it 'be a simple stringified number when there is one die roll' do
|
|
174
174
|
die_result.add_roll(3)
|
|
175
175
|
expect(die_result.explain_value).to eql '3'
|
|
176
176
|
end
|
|
177
177
|
|
|
178
|
-
it '
|
|
178
|
+
it 'describe all single rolls made and how they combine' do
|
|
179
179
|
die_result.add_roll(6)
|
|
180
180
|
expect(die_result.explain_value).to eql '6'
|
|
181
181
|
|
|
@@ -196,59 +196,59 @@ describe GamesDice::DieResult do
|
|
|
196
196
|
end
|
|
197
197
|
end
|
|
198
198
|
|
|
199
|
-
it '
|
|
200
|
-
die_result =
|
|
201
|
-
expect(
|
|
202
|
-
expect(
|
|
203
|
-
expect(
|
|
204
|
-
expect(
|
|
199
|
+
it 'combine via +,- and * intuitively based on #value' do
|
|
200
|
+
die_result = described_class.new(7)
|
|
201
|
+
expect(die_result + 3).to be 10
|
|
202
|
+
expect(4 + die_result).to be 11
|
|
203
|
+
expect(die_result - 2).to be 5
|
|
204
|
+
expect(9 - die_result).to be 2
|
|
205
205
|
|
|
206
|
-
expect(
|
|
207
|
-
expect(
|
|
206
|
+
expect(die_result + 7.7).to be 14.7
|
|
207
|
+
expect(4.1 + die_result).to be 11.1
|
|
208
208
|
|
|
209
|
-
expect(
|
|
210
|
-
expect(
|
|
209
|
+
expect(die_result * 2).to be 14
|
|
210
|
+
expect(1 * die_result).to be 7
|
|
211
211
|
|
|
212
|
-
other_die_result =
|
|
212
|
+
other_die_result = described_class.new(6)
|
|
213
213
|
other_die_result.add_roll(6, :reroll_add)
|
|
214
|
-
expect(
|
|
215
|
-
expect(
|
|
214
|
+
expect(die_result + other_die_result).to be 19
|
|
215
|
+
expect(other_die_result - die_result).to be 5
|
|
216
216
|
end
|
|
217
217
|
|
|
218
|
-
it '
|
|
219
|
-
die_result =
|
|
218
|
+
it 'support comparison with >,<,>=,<= as if it were an integer, based on #value' do
|
|
219
|
+
die_result = described_class.new(7)
|
|
220
220
|
|
|
221
|
-
expect(
|
|
222
|
-
expect(
|
|
223
|
-
expect(
|
|
224
|
-
expect(
|
|
225
|
-
expect(
|
|
226
|
-
expect(
|
|
227
|
-
expect(
|
|
228
|
-
expect(
|
|
221
|
+
expect(die_result > 3).to be true
|
|
222
|
+
expect(die_result < 14).to be true
|
|
223
|
+
expect(die_result >= 7).to be true
|
|
224
|
+
expect(die_result <= 9.5).to be true
|
|
225
|
+
expect(die_result < 3).to be false
|
|
226
|
+
expect(die_result > 14).to be false
|
|
227
|
+
expect(die_result <= 8).to be true
|
|
228
|
+
expect(die_result >= 14).to be false
|
|
229
229
|
|
|
230
|
-
other_die_result =
|
|
230
|
+
other_die_result = described_class.new(6)
|
|
231
231
|
other_die_result.add_roll(6, :reroll_add)
|
|
232
|
-
expect(
|
|
233
|
-
expect(
|
|
234
|
-
expect(
|
|
235
|
-
expect(
|
|
236
|
-
expect(
|
|
237
|
-
expect(
|
|
238
|
-
expect(
|
|
239
|
-
expect(
|
|
232
|
+
expect(die_result > other_die_result).to be false
|
|
233
|
+
expect(other_die_result > die_result).to be true
|
|
234
|
+
expect(die_result >= other_die_result).to be false
|
|
235
|
+
expect(other_die_result >= die_result).to be true
|
|
236
|
+
expect(die_result < other_die_result).to be true
|
|
237
|
+
expect(other_die_result < die_result).to be false
|
|
238
|
+
expect(die_result <= other_die_result).to be true
|
|
239
|
+
expect(other_die_result <= die_result).to be false
|
|
240
240
|
end
|
|
241
241
|
|
|
242
|
-
it '
|
|
242
|
+
it 'sort, based on #value' do
|
|
243
243
|
die_results = [
|
|
244
|
-
|
|
244
|
+
described_class.new(7), described_class.new(5), described_class.new(8), described_class.new(3)
|
|
245
245
|
]
|
|
246
246
|
|
|
247
247
|
die_results.sort!
|
|
248
248
|
|
|
249
|
-
expect(die_results[0].value).to
|
|
250
|
-
expect(die_results[1].value).to
|
|
251
|
-
expect(die_results[2].value).to
|
|
252
|
-
expect(die_results[3].value).to
|
|
249
|
+
expect(die_results[0].value).to be 3
|
|
250
|
+
expect(die_results[1].value).to be 5
|
|
251
|
+
expect(die_results[2].value).to be 7
|
|
252
|
+
expect(die_results[3].value).to be 8
|
|
253
253
|
end
|
|
254
254
|
end
|
data/spec/die_spec.rb
CHANGED
|
@@ -9,16 +9,16 @@ describe GamesDice::Die do
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
describe '#new' do
|
|
12
|
-
it '
|
|
13
|
-
die =
|
|
14
|
-
expect(die.min).to
|
|
15
|
-
expect(die.max).to
|
|
16
|
-
expect(die.sides).to
|
|
12
|
+
it 'return an object that represents e.g. a six-sided die' do
|
|
13
|
+
die = described_class.new(6)
|
|
14
|
+
expect(die.min).to be 1
|
|
15
|
+
expect(die.max).to be 6
|
|
16
|
+
expect(die.sides).to be 6
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
it '
|
|
19
|
+
it 'accept any object with a rand(Integer) method as the second param' do
|
|
20
20
|
prng = TestPRNG.new
|
|
21
|
-
die =
|
|
21
|
+
die = described_class.new(20, prng)
|
|
22
22
|
[16, 7, 3, 11, 16, 18, 20, 7].each do |expected|
|
|
23
23
|
expect(die.roll).to eql expected
|
|
24
24
|
expect(die.result).to eql expected
|
|
@@ -27,8 +27,8 @@ describe GamesDice::Die do
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
describe '#roll and #result' do
|
|
30
|
-
it "
|
|
31
|
-
die =
|
|
30
|
+
it "return results based on Ruby's internal rand() by default" do
|
|
31
|
+
die = described_class.new(10)
|
|
32
32
|
[5, 4, 10, 4, 7, 8, 1, 9].each do |expected|
|
|
33
33
|
expect(die.roll).to eql expected
|
|
34
34
|
expect(die.result).to eql expected
|
|
@@ -37,16 +37,16 @@ describe GamesDice::Die do
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
describe '#min and #max' do
|
|
40
|
-
it '
|
|
41
|
-
die =
|
|
42
|
-
expect(die.min).to
|
|
43
|
-
expect(die.max).to
|
|
40
|
+
it 'calculate correct min, max' do
|
|
41
|
+
die = described_class.new(20)
|
|
42
|
+
expect(die.min).to be 1
|
|
43
|
+
expect(die.max).to be 20
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
describe '#probabilities' do
|
|
48
|
-
it "
|
|
49
|
-
die =
|
|
48
|
+
it "return the die's probability distribution as a GamesDice::Probabilities object" do
|
|
49
|
+
die = described_class.new(6)
|
|
50
50
|
probs = die.probabilities
|
|
51
51
|
expect(probs).to be_a GamesDice::Probabilities
|
|
52
52
|
|
|
@@ -64,15 +64,15 @@ describe GamesDice::Die do
|
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
describe '#all_values' do
|
|
67
|
-
it '
|
|
68
|
-
die =
|
|
67
|
+
it 'return array with one result value per side' do
|
|
68
|
+
die = described_class.new(8)
|
|
69
69
|
expect(die.all_values).to eql [1, 2, 3, 4, 5, 6, 7, 8]
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
describe '#each_value' do
|
|
74
|
-
it '
|
|
75
|
-
die =
|
|
74
|
+
it 'iterate through all sides of the die' do
|
|
75
|
+
die = described_class.new(10)
|
|
76
76
|
arr = []
|
|
77
77
|
die.each_value { |x| arr << x }
|
|
78
78
|
expect(arr).to eql [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
data/spec/helpers.rb
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
# games_dice/spec/helpers.rb
|
|
4
4
|
require 'pathname'
|
|
5
|
-
require 'coveralls'
|
|
6
|
-
Coveralls.wear!
|
|
7
5
|
|
|
8
6
|
require 'games_dice'
|
|
9
7
|
|
|
@@ -55,8 +53,8 @@ RSpec::Matchers.define :be_valid_distribution do
|
|
|
55
53
|
elsif given.values.any? { |v| v < 0.0 || v > 1.0 }
|
|
56
54
|
bad_value = given.values.find { |v| v < 0.0 || v > 1.0 }
|
|
57
55
|
@error = "all values should be in range (0.0..1.0), but found #{bad_value}"
|
|
58
|
-
elsif (1.0 - given.values.
|
|
59
|
-
total_probs = given.values.
|
|
56
|
+
elsif (1.0 - given.values.sum).abs > 1e-6
|
|
57
|
+
total_probs = given.values.sum
|
|
60
58
|
@error = "sum of values should be 1.0, but got #{total_probs}"
|
|
61
59
|
end
|
|
62
60
|
!@error
|
data/spec/map_rule_spec.rb
CHANGED
|
@@ -4,36 +4,36 @@ require 'helpers'
|
|
|
4
4
|
|
|
5
5
|
describe GamesDice::MapRule do
|
|
6
6
|
describe '#new' do
|
|
7
|
-
it '
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
it 'accept self-consistent operator/value pairs as a trigger' do
|
|
8
|
+
expect { described_class.new(5, :>, 1) }.not_to raise_error
|
|
9
|
+
expect { described_class.new(1..5, :member?, 17) }.not_to raise_error
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
it '
|
|
13
|
-
expect
|
|
14
|
-
expect
|
|
12
|
+
it 'reject inconsistent operator/value pairs for a trigger' do
|
|
13
|
+
expect { described_class.new(5, :member?, -1) }.to raise_error(ArgumentError)
|
|
14
|
+
expect { described_class.new(1..5, :>, 12) }.to raise_error(ArgumentError)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
it '
|
|
18
|
-
expect
|
|
19
|
-
expect
|
|
17
|
+
it 'reject non-Integer map results' do
|
|
18
|
+
expect { described_class.new(5, :>, :reroll_again) }.to raise_error(TypeError)
|
|
19
|
+
expect { described_class.new(1..5, :member?, 'foo') }.to raise_error(TypeError)
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
describe '#map_from' do
|
|
24
|
-
it '
|
|
25
|
-
rule =
|
|
26
|
-
expect(rule.map_from(4)).to
|
|
24
|
+
it 'return the mapped value for a match' do
|
|
25
|
+
rule = described_class.new(5, :>, -1)
|
|
26
|
+
expect(rule.map_from(4)).to be(-1)
|
|
27
27
|
|
|
28
|
-
rule =
|
|
29
|
-
expect(rule.map_from(4)).to
|
|
28
|
+
rule = described_class.new(1..5, :member?, 3)
|
|
29
|
+
expect(rule.map_from(4)).to be 3
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
it '
|
|
33
|
-
rule =
|
|
32
|
+
it 'return nil for no match' do
|
|
33
|
+
rule = described_class.new(5, :>, -1)
|
|
34
34
|
expect(rule.map_from(6)).to be_nil
|
|
35
35
|
|
|
36
|
-
rule =
|
|
36
|
+
rule = described_class.new(1..5, :member?, 3)
|
|
37
37
|
expect(rule.map_from(6)).to be_nil
|
|
38
38
|
end
|
|
39
39
|
end
|
data/spec/parser_spec.rb
CHANGED
|
@@ -4,9 +4,9 @@ require 'helpers'
|
|
|
4
4
|
|
|
5
5
|
describe GamesDice::Parser do
|
|
6
6
|
describe '#parse' do
|
|
7
|
-
let(:parser) {
|
|
7
|
+
let(:parser) { described_class.new }
|
|
8
8
|
|
|
9
|
-
it '
|
|
9
|
+
it 'parse simple dice sums' do
|
|
10
10
|
variations = {
|
|
11
11
|
'1d6' => { bunches: [{ ndice: 1, sides: 6, multiplier: 1 }], offset: 0 },
|
|
12
12
|
'2d8-1d4' => { bunches: [{ ndice: 2, sides: 8, multiplier: 1 }, { ndice: 1, sides: 4, multiplier: -1 }],
|
|
@@ -30,7 +30,7 @@ describe GamesDice::Parser do
|
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
it "
|
|
33
|
+
it "parse 'NdXrY' as 'roll N times X-sided dice, re-roll and replace a Y or less (once)'" do
|
|
34
34
|
variations = {
|
|
35
35
|
'1d6r1' => { bunches: [{ ndice: 1, sides: 6, multiplier: 1, rerolls: [[1, :>=, :reroll_replace]] }],
|
|
36
36
|
offset: 0 },
|
|
@@ -45,7 +45,7 @@ describe GamesDice::Parser do
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
it "
|
|
48
|
+
it "parse 'NdXmZ' as 'roll N times X-sided dice, a value of Z or more equals 1 (success)'" do
|
|
49
49
|
variations = {
|
|
50
50
|
'5d6m6' => { bunches: [{ ndice: 5, sides: 6, multiplier: 1, maps: [[6, :<=, 1]] }],
|
|
51
51
|
offset: 0 },
|
|
@@ -58,7 +58,7 @@ describe GamesDice::Parser do
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
it "
|
|
61
|
+
it "parse 'NdXkC' as 'roll N times X-sided dice, add together the best C'" do
|
|
62
62
|
variations = {
|
|
63
63
|
'5d10k3' => { bunches: [{ ndice: 5, sides: 10, multiplier: 1, keep_mode: :keep_best, keep_number: 3 }],
|
|
64
64
|
offset: 0 }
|
|
@@ -69,7 +69,7 @@ describe GamesDice::Parser do
|
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
it "
|
|
72
|
+
it "parse 'NdXx' as 'roll N times X-sided *exploding* dice'" do
|
|
73
73
|
variations = {
|
|
74
74
|
'5d10x' => { bunches: [{ ndice: 5, sides: 10, multiplier: 1, rerolls: [[10, :==, :reroll_add]] }],
|
|
75
75
|
offset: 0 },
|
|
@@ -82,7 +82,7 @@ describe GamesDice::Parser do
|
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
it '
|
|
85
|
+
it 'successfully parse combinations of modifiers in any valid order' do
|
|
86
86
|
variations = {
|
|
87
87
|
'5d10r1x' => {
|
|
88
88
|
bunches: [{ ndice: 5, sides: 10, multiplier: 1,
|