Module: DiceBag

Defined in:
lib/dicebag.rb,
lib/dicebag/roll.rb,
lib/dicebag/parser.rb,
lib/dicebag/result.rb,
lib/dicebag/roll_part.rb,
lib/dicebag/transform.rb,
lib/dicebag/label_part.rb,
lib/dicebag/simple_part.rb,
lib/dicebag/static_part.rb

Overview

This continues definining the DiceBag module.

Defined Under Namespace

Classes: DiceBagError, LabelPart, Parser, Result, Roll, RollPart, SimplePart, StaticPart, Transform

Constant Summary collapse

DEFAULT_ROLL =
'1d6'.freeze

Class Method Summary collapse

Class Method Details

.normalize_array(part) ⇒ Object



67
68
69
# File 'lib/dicebag.rb', line 67

def self.normalize_array(part)
  [normalize_op(part.first), normalize_value(part.last)]
end

.normalize_drop_keep(xdx) ⇒ Object

Make sure there are enough dice to handle both Drop and Keep values. If not, both are reset to 0. Harsh.



150
151
152
153
154
155
156
157
158
159
160
# File 'lib/dicebag.rb', line 150

def self.normalize_drop_keep(xdx)
  drop = xdx[:options].fetch(:drop, 0)
  keep = xdx[:options].fetch(:keep, 0)

  if (drop + keep) >= xdx[:count]
    xdx[:options][:drop] = 0
    xdx[:options][:keep] = 0

    xdx[:notes].push 'Drop and Keep Conflict. Both reset to 0.'
  end
end

.normalize_explode(xdx) ⇒ Object

Prevent Explosion abuse.



124
125
126
127
128
129
130
131
132
133
134
# File 'lib/dicebag.rb', line 124

def self.normalize_explode(xdx)
  return unless xdx[:options].key? :explode

  explode = xdx[:options][:explode]

  if explode.nil? || explode.zero? || explode == 1
    xdx[:options][:explode] = xdx[:sides]

    xdx[:notes].push("Explode set to #{xdx[:sides]}")
  end
end

.normalize_hash(part) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
# File 'lib/dicebag.rb', line 55

def self.normalize_hash(part)
  return [:label, LabelPart.new(part[:label])] if part.key? :label

  if part.key? :start
    xdx = normalize_xdx(part[:start])

    return [:start, RollPart.new(xdx)]
  end

  part
end

.normalize_op(op) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/dicebag.rb', line 71

def self.normalize_op(op)
  # We swap out the strings for symbols.
  # If the op is not one of the arithimetic
  # operators, then the op itself is returned.
  # (This should only happen on :start arrays.)
  case op
  when '+' then :add
  when '-' then :sub
  when '*' then :mul
  when '/' then :div
  else
    op
  end
end

.normalize_options(xdx) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/dicebag.rb', line 110

def self.normalize_options(xdx)
  if xdx[:options].empty?
    xdx.delete(:options)
  else
    normalize_explode xdx
    normalize_reroll xdx
    normalize_drop_keep xdx
    normalize_target xdx
  end

  xdx
end

.normalize_reroll(xdx) ⇒ Object

Prevent Reroll abuse.



137
138
139
140
141
142
143
144
145
# File 'lib/dicebag.rb', line 137

def self.normalize_reroll(xdx)
  return unless xdx[:options].key? :reroll

  if xdx[:options][:reroll] >= xdx[:sides]
    xdx[:options][:reroll] = 0

    xdx[:notes].push 'Reroll reset to 0.'
  end
end

.normalize_target(xdx) ⇒ Object

Finally, if we have a target number, make sure it is equal to or less than the dice sides and greater than 0, otherwise, set it to 0 (aka no target number) and add a note.



165
166
167
168
169
170
171
172
173
174
175
# File 'lib/dicebag.rb', line 165

def self.normalize_target(xdx)
  return unless xdx[:options].key? :target

  target = xdx[:options][:target]

  return if target >= 0 && target <= xdx[:sides]

  xdx[:options][:target] = 0

  xdx[:notes].push 'Target number too large or is negative; reset to 0.'
end

.normalize_tree(tree) ⇒ Object

This takes the parsed tree, AFTER it has been through the Transform class, and massages the data a bit more, to ease the iteration that happens in the Roll class. It will convert all values into the correct *Part class.



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/dicebag.rb', line 42

def self.normalize_tree(tree)
  tree.collect do |part|
    case part
    when Hash
      normalize_hash part
    when Array
      normalize_array part
    else
      part
    end
  end
end

.normalize_value(val) ⇒ Object



86
87
88
# File 'lib/dicebag.rb', line 86

def self.normalize_value(val)
  val.is_a?(Hash) ? RollPart.new(normalize_xdx(val)) : StaticPart.new(val)
end

.normalize_xdx(xdx) ⇒ Object

This further massages the xDx hashes.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/dicebag.rb', line 91

def self.normalize_xdx(xdx)
  count = xdx[:xdx][:count]
  sides = xdx[:xdx][:sides]

  # Delete the no longer needed :xdx key.
  xdx.delete(:xdx)

  # Default to at least 1 die.
  count = 1 if count.zero? || count.nil?

  # Set the :count and :sides keys directly
  # and set the notes array.
  xdx[:count] = count
  xdx[:sides] = sides
  xdx[:notes] = []

  normalize_options xdx
end

.parse(dstr = '') ⇒ Object

This is the wrapper for the parse, transform, and normalize calls. This is called by the Roll class, but may be called to get the raw returned array of parsed bits for other purposes.



181
182
183
184
185
186
# File 'lib/dicebag.rb', line 181

def self.parse(dstr = '')
  tree = Parser.new.parse(dstr)
  ast  = Transform.new.apply(tree)

  normalize_tree ast
end