games_dice 0.1.2 → 0.1.3
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/README.md +39 -9
- data/lib/games_dice/parser.rb +59 -12
- data/lib/games_dice/version.rb +1 -1
- data/spec/readme_spec.rb +71 -0
- metadata +4 -4
data/README.md
CHANGED
@@ -54,11 +54,10 @@ Or install it yourself as:
|
|
54
54
|
## Library API
|
55
55
|
|
56
56
|
Although you can refer to the documentation for the contained classes, and use it if needed to
|
57
|
-
build some exotic dice systems,
|
58
|
-
|
59
|
-
dice rolls, explain the results or calculate probabilties as required.
|
57
|
+
build some exotic dice systems, all you need to know to access the core features is described
|
58
|
+
here.
|
60
59
|
|
61
|
-
### GamesDice factory
|
60
|
+
### GamesDice factory method
|
62
61
|
|
63
62
|
#### GamesDice.create
|
64
63
|
|
@@ -217,23 +216,54 @@ A die modifier can also be a single letter plus an integer value, e.g.
|
|
217
216
|
|
218
217
|
1d6r1
|
219
218
|
|
220
|
-
|
221
|
-
|
219
|
+
You can add comma-seperated parameters to a modifier by using a ":" (colon) character after the
|
220
|
+
modifier letter, and a "." (full stop) to signify the end of the parameters. What parameters are
|
221
|
+
accepted, and what they mean, depends on the modifier:
|
222
222
|
|
223
|
-
5d10r
|
223
|
+
5d10r:>8,add.
|
224
|
+
|
225
|
+
You can use more than one modifier. Modifiers should be separated by a "." (full stop) character, although
|
226
|
+
this is optional if you use modifiers without parameters:
|
227
|
+
|
228
|
+
5d10r:10,add.k2
|
229
|
+
5d10xk2
|
230
|
+
5d10x.k2
|
231
|
+
|
232
|
+
are all equivalent.
|
224
233
|
|
225
234
|
#### Rerolls
|
226
235
|
|
227
236
|
You can specify that dice rolling certain values should be re-rolled, and how that re-roll should be
|
228
237
|
interpretted.
|
229
238
|
|
230
|
-
The simple form specifies a low value that will automatically trigger a
|
239
|
+
The simple form specifies a low value that will automatically trigger a re-roll and replace:
|
231
240
|
|
232
241
|
1d6r1
|
233
242
|
|
234
243
|
When rolled, this die will score from 1 to 6. If it rolls a 1, it will roll again automatically
|
235
244
|
and use that result instead.
|
236
245
|
|
246
|
+
The full version of this modifier, allows you to specify from 1 to 3 parameters:
|
247
|
+
|
248
|
+
1d10r:[VALUE_COMPARISON],[REROLL_TYPE],[LIMIT].
|
249
|
+
|
250
|
+
Where:
|
251
|
+
|
252
|
+
* VALUE_COMPARISON is one of >, >=, == (default), <= < plus an integer to set conditions on when the reroll should occur
|
253
|
+
* REROLL_TYPE is one of
|
254
|
+
* replace (default) - use the new value in place of existing value for the die
|
255
|
+
* add - add result of reroll to running total, and ignore any subtract rules
|
256
|
+
* subtract - subtract result of reroll from running total, and reverse sense of any further add results
|
257
|
+
* use_best - use the new value if it is higher than the existing value
|
258
|
+
* use_worst - use the new value if it is higher than the existing value
|
259
|
+
* LIMIT is an integer that sets the maximum number of times that the rule can be triggered, the default is 1000
|
260
|
+
|
261
|
+
Examples:
|
262
|
+
|
263
|
+
1d6r:1. # Same as "1d6r1"
|
264
|
+
1d10r:10,replace,1. #
|
265
|
+
1d20r:<=10,use_best,1. # Roll a 20-sided die, re-roll a result if 10 or lower, and use best result
|
266
|
+
|
237
267
|
#### Maps
|
238
268
|
|
239
269
|
You can specify that the value shown on each die is converted to some other set of values. If
|
@@ -264,7 +294,7 @@ short codes.
|
|
264
294
|
|
265
295
|
This is an alias for "exploding" dice:
|
266
296
|
|
267
|
-
5d10x
|
297
|
+
5d10x # Same as '5d10r:10,add.'
|
268
298
|
|
269
299
|
When rolled, this will score from 5 to theoretically any number, as results of 10 on any die mean that
|
270
300
|
die rolls again and the result is added on.
|
data/lib/games_dice/parser.rb
CHANGED
@@ -3,16 +3,17 @@ require 'parslet'
|
|
3
3
|
# converts string dice descriptions to data usable for the GamesDice::Dice constructor
|
4
4
|
class GamesDice::Parser < Parslet::Parser
|
5
5
|
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# NdXr[Z,add] - a roll of N dice, sides X, re-roll and add on a result of Z
|
9
|
-
# NdXr[Y..Z,add] - a roll of N dice, sides X, re-roll and add on a result of Y..Z
|
10
|
-
# NdXm[>=Z,A] - mapped dice, values greater than or equal to Z score A (unmapped values score 0 by default)
|
6
|
+
# These are the Parslet rules that define the dice grammar. It's an inefficient and over-complex
|
7
|
+
# use of Parslet, and could do with logical a clean-up.
|
11
8
|
|
12
|
-
# These are the Parslet rules that define the dice grammar
|
13
9
|
rule(:integer) { match('[0-9]').repeat(1) }
|
14
10
|
rule(:range) { integer.as(:range_start) >> str('..') >> integer.as(:range_end) }
|
15
11
|
rule(:dlabel) { match('[d]') }
|
12
|
+
rule(:space) { match('\s').repeat(1) }
|
13
|
+
rule(:space?) { space.maybe }
|
14
|
+
rule(:underscore) { str('_').repeat(1) }
|
15
|
+
rule(:underscore?) { space.maybe }
|
16
|
+
|
16
17
|
rule(:bunch_start) { integer.as(:ndice) >> dlabel >> integer.as(:sides) }
|
17
18
|
|
18
19
|
rule(:reroll_label) { match(['r']).as(:reroll) }
|
@@ -23,12 +24,33 @@ class GamesDice::Parser < Parslet::Parser
|
|
23
24
|
rule(:single_modifier) { alias_label }
|
24
25
|
rule(:modifier_label) { reroll_label | keep_label | map_label }
|
25
26
|
rule(:simple_modifier) { modifier_label >> integer.as(:simple_value) }
|
26
|
-
rule(:
|
27
|
+
rule(:comparison_op) { str('>=') | str('<=') | str('==') | str('>') | str('<') }
|
28
|
+
rule(:ctl_string) { match('[a-z_]').repeat(1) }
|
29
|
+
rule(:output_string) { match('[A-Za-z0-9_]').repeat(1) }
|
30
|
+
|
31
|
+
rule(:opint_or_int) { (comparison_op.as(:comparison) >> integer.as(:compare_num)) | integer.as(:compare_num) }
|
32
|
+
rule(:comma) { str(',') }
|
33
|
+
rule(:stop) { str('.') }
|
34
|
+
|
35
|
+
rule(:condition_only) { opint_or_int.as(:condition) }
|
36
|
+
|
37
|
+
rule(:condition_and_type) { opint_or_int.as(:condition) >> comma >> ctl_string.as(:type) }
|
38
|
+
rule(:condition_and_num) { opint_or_int.as(:condition) >> comma >> integer.as(:num) }
|
39
|
+
|
40
|
+
rule(:condition_type_and_num) { opint_or_int.as(:condition) >> comma >> ctl_string.as(:type) >> comma >> integer.as(:num) }
|
41
|
+
rule(:condition_num_and_output) { opint_or_int.as(:condition) >> comma >> integer.as(:num) >> comma >> ctl_string.as(:output) }
|
42
|
+
|
43
|
+
rule(:reroll_params) { condition_type_and_num | condition_and_type | condition_only }
|
44
|
+
rule(:map_params) { condition_num_and_output | condition_and_num | condition_only }
|
45
|
+
|
46
|
+
rule(:full_reroll) { reroll_label >> str(':') >> reroll_params >> stop }
|
47
|
+
rule(:full_map) { map_label >> str(':') >> map_params >> stop }
|
48
|
+
|
49
|
+
rule(:complex_modifier) { full_reroll | full_map }
|
27
50
|
|
28
|
-
rule(:bunch_modifier) { single_modifier | simple_modifier }
|
51
|
+
rule(:bunch_modifier) { complex_modifier | ( single_modifier >> stop.maybe ) | ( simple_modifier >> stop.maybe ) }
|
29
52
|
rule(:bunch) { bunch_start >> bunch_modifier.repeat.as(:mods) }
|
30
|
-
|
31
|
-
rule(:space?) { space.maybe }
|
53
|
+
|
32
54
|
rule(:operator) { match('[+-]').as(:op) >> space? }
|
33
55
|
rule(:add_bunch) { operator >> bunch >> space? }
|
34
56
|
rule(:add_constant) { operator >> integer.as(:constant) >> space? }
|
@@ -116,8 +138,18 @@ class GamesDice::Parser < Parslet::Parser
|
|
116
138
|
out_hash[:rerolls] ||= []
|
117
139
|
if reroll_mod[:simple_value]
|
118
140
|
out_hash[:rerolls] << [ reroll_mod[:simple_value].to_i, :>=, :reroll_replace, 1 ]
|
141
|
+
return
|
142
|
+
end
|
143
|
+
# Typical reroll_mod: {:reroll=>"r"@5, :condition=>{:compare_num=>"10"@7}, :type=>"add"@10}
|
144
|
+
op = get_op_symbol( reroll_mod[:condition][:comparison] || '==' )
|
145
|
+
v = reroll_mod[:condition][:compare_num].to_i
|
146
|
+
type = ( 'reroll_' + ( reroll_mod[:type] || 'replace' ) ).to_sym
|
147
|
+
|
148
|
+
if reroll_mod[:num]
|
149
|
+
out_hash[:rerolls] << [ v, op, type, reroll_mod[:num].to_i ]
|
150
|
+
else
|
151
|
+
out_hash[:rerolls] << [ v, op, type ]
|
119
152
|
end
|
120
|
-
# TODO: Handle complex descriptions
|
121
153
|
end
|
122
154
|
|
123
155
|
# Called for any parsed keeper mode
|
@@ -137,7 +169,22 @@ class GamesDice::Parser < Parslet::Parser
|
|
137
169
|
out_hash[:maps] << [ map_mod[:simple_value].to_i, :<=, 1 ]
|
138
170
|
return
|
139
171
|
end
|
140
|
-
|
172
|
+
|
173
|
+
# Typical
|
174
|
+
end
|
175
|
+
|
176
|
+
# The dice description language uses (r).op.x, whilst GamesDice::RerollRule uses x.op.(r), so
|
177
|
+
# as well as converting to a symbol, we must reverse sense of input to constructor
|
178
|
+
OP_CONVERSION = {
|
179
|
+
'==' => :==,
|
180
|
+
'>=' => :<=,
|
181
|
+
'>' => :<,
|
182
|
+
'<' => :>,
|
183
|
+
'<=' => :>=,
|
184
|
+
}
|
185
|
+
|
186
|
+
def get_op_symbol parsed_op_string
|
187
|
+
OP_CONVERSION[ parsed_op_string.to_s ]
|
141
188
|
end
|
142
189
|
|
143
190
|
end # class Parser
|
data/lib/games_dice/version.rb
CHANGED
data/spec/readme_spec.rb
CHANGED
@@ -146,3 +146,74 @@ describe GamesDice::Probabilities do
|
|
146
146
|
end
|
147
147
|
|
148
148
|
end # describe GamesDice::Probabilities
|
149
|
+
|
150
|
+
describe 'String Dice Description' do
|
151
|
+
|
152
|
+
before :each do
|
153
|
+
srand(35241)
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "'1d6'" do
|
157
|
+
it "returns expected results from rolling" do
|
158
|
+
d = GamesDice.create '1d6'
|
159
|
+
(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]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "'2d6 + 1d4'" do
|
164
|
+
it "returns expected results from rolling" do
|
165
|
+
d = GamesDice.create '2d6 + 1d4'
|
166
|
+
(1..5).map { |n| d.roll }.should == [11, 10, 12, 12, 14]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "'1d100 + 1d20 - 5'" do
|
171
|
+
it "returns expected results from rolling" do
|
172
|
+
d = GamesDice.create '1d100 + 1d20 - 5'
|
173
|
+
(1..5).map { |n| d.roll }.should == [75, 78, 24, 102, 32]
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "'1d10x'" do
|
178
|
+
it "returns expected results from rolling" do
|
179
|
+
d = GamesDice.create '1d10x'
|
180
|
+
(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]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "'1d6r1'" do
|
185
|
+
it "returns expected results from rolling" do
|
186
|
+
d = GamesDice.create '1d6r1'
|
187
|
+
(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]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe "'5d10r:10,add.k2'" do
|
192
|
+
it "returns expected results from rolling" do
|
193
|
+
d = GamesDice.create '5d10r:10,add.k2'
|
194
|
+
(1..5).map { |n| d.roll }.should == [13, 13, 14, 38, 15]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "'3d10m6'" do
|
199
|
+
it "returns expected results from rolling" do
|
200
|
+
d = GamesDice.create '3d10m6'
|
201
|
+
(1..6).map { |n| d.roll }.should == [0, 3, 1, 1, 3, 2]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "'5d10k2'" do
|
206
|
+
it "returns expected results from rolling" do
|
207
|
+
d = GamesDice.create '5d10k2'
|
208
|
+
(1..5).map { |n| d.roll }.should == [13, 13, 14, 19, 19]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "'5d10x'" do
|
213
|
+
it "returns expected results from rolling" do
|
214
|
+
d = GamesDice.create '5d10x'
|
215
|
+
(1..5).map { |n| d.roll }.should == [22, 22, 31, 53, 25]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: games_dice
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -112,7 +112,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
112
112
|
version: '0'
|
113
113
|
segments:
|
114
114
|
- 0
|
115
|
-
hash: -
|
115
|
+
hash: -4383036419295474875
|
116
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
117
|
none: false
|
118
118
|
requirements:
|
@@ -121,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
121
|
version: '0'
|
122
122
|
segments:
|
123
123
|
- 0
|
124
|
-
hash: -
|
124
|
+
hash: -4383036419295474875
|
125
125
|
requirements: []
|
126
126
|
rubyforge_project:
|
127
127
|
rubygems_version: 1.8.24
|