Skip to content

Instantly share code, notes, and snippets.

@madx
Created January 5, 2011 15:13
Show Gist options
  • Save madx/766430 to your computer and use it in GitHub Desktop.
Save madx/766430 to your computer and use it in GitHub Desktop.
Dice rolling expressions in Ruby w/ Treetop
require 'forwardable'
module Dexp
class Roll
attr_reader :count, :sides, :modifier
def initialize(count, sides, modifier)
@count, @sides, @modifier = count, sides, modifier
end
def results
modifier.call(RollProxy.new(self))
end
end
class RollProxy
extend Forwardable
def initialize(roll)
@roll = roll
@array = Array.new(roll.count) { rand(roll.sides) }
end
def_delegators :@array, :max, :min, :sort
def sum
@array.inject(0) {|a,e| a + e }
end
def open
@array += @roll.results if @array.any? {|e| e == @roll.sides - 1 }
return @array
end
def inspect
@array.inspect
end
end
module IntegerNode
def value
text_value.to_i
end
end
def OperatorNode(op)
return Module.new.tap {|mod|
mod.send(:define_method, :value) {
lambda {|a|
a.map {|e| e.send(op, number.value)}
}
}
}
end
end
require 'dexp'
grammar Dice
rule expression
count:(number?) 'd' sides modifier {
def roller
Dexp::Roll.new(count.value, sides.value, modifier.value)
end
}
end
rule number
[1-9] [0-9]* <Dexp::IntegerNode>
end
rule modifier
'+' number <Dexp::OperatorNode(:+)>
/
'-' number <Dexp::OperatorNode(:-)>
/
function
/
'' {
def value
lambda {|a| a }
end
}
end
rule function
'.' fun:('max' / 'min' / 'sum' / 'sort' / 'open') {
def value
lambda {|a| a.send(fun.text_value.to_sym) }
end
}
end
rule sides
('100' / '20' / '12' / '10' / '8' / '6' / '4' / '2') <Dexp::IntegerNode>
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment