class LSystem::RulesEngine
An engine for iterating over successive applications of the L-System's ruleset to its axiom.
Public Class Methods
Create a new rules engine for an L-System. If the block
is present, it is called with the new instance as self
.
# File lib/l_system/rules_engine.rb, line 21 def initialize( &block ) @variables = Set.new @constants = Set.new @axiom = nil @rules = [] @rules_as_hash = nil self.instance_eval( &block ) if block end
Public Instance Methods
Return the system's variables and constants.
# File lib/l_system/rules_engine.rb, line 84 def alphabet return @variables | @constants end
Apply the system's rules to the given state
and return the result.
# File lib/l_system/rules_engine.rb, line 121 def apply_rules( state ) rules_hash = self.rules_as_hash return state.each_char.with_object( String.new(encoding: 'utf-8') ) do |char, new_state| new_state << rules_hash[ char ] end end
Get/set the axiom of the system.
# File lib/l_system/rules_engine.rb, line 90 def axiom( new_value=nil ) self.axiom = new_value if new_value return @axiom end
Set the axiom of the system.
# File lib/l_system/rules_engine.rb, line 97 def axiom=( new_value ) @axiom = new_value end
Get/set the system's constants (the static parts of its alphabet).
# File lib/l_system/rules_engine.rb, line 63 def constants( *new_values ) self.constants = new_values unless new_values.empty? return @constants.dup end
Set the systems constants to new_values
.
# File lib/l_system/rules_engine.rb, line 70 def constants=( new_values ) @rules_as_hash = nil new_values = Set.new( new_values, &:to_s ) unless new_values.disjoint?( self.variables ) common_char = (new_values & self.variables).to_a.first raise ArgumentError, "%p is already included in the variable set" % [ common_char ] end @constants = new_values end
Yield each successive generation to the given block
, or return an Enumerator that will do so if no block is given.
# File lib/l_system/rules_engine.rb, line 131 def each( &block ) iter = Enumerator.new do |yielder| state = new_state = self.axiom.dup begin yielder.yield( new_state ) state = new_state new_state = self.apply_rules( state ) end until state == new_state end return iter unless block return iter.each( &block ) end
Get/set the system's rules.
# File lib/l_system/rules_engine.rb, line 103 def rules( *new_values ) self.rules = new_values unless new_values.empty? return @rules end
Set the system's rules.
# File lib/l_system/rules_engine.rb, line 110 def rules=( new_values ) @rules_as_hash = nil @rules = Array( new_values ).map( &:to_s ) end
Get/set the system's variables (the replaceable parts of its alphabet).
# File lib/l_system/rules_engine.rb, line 42 def variables( *new_values ) self.variables = new_values unless new_values.empty? return @variables.dup end
Set the systems variables to new_values
.
# File lib/l_system/rules_engine.rb, line 49 def variables=( new_values ) @rules_as_hash = nil new_values = Set.new( new_values, &:to_s ) unless new_values.disjoint?( self.constants ) common_char = (new_values & self.constants).to_a.first raise ArgumentError, "%p is already included in the constant set" % [ common_char ] end @variables = new_values end
Protected Instance Methods
Return a tuple of the predecessor and successor of the given rule
.
# File lib/l_system/rules_engine.rb, line 170 def parse_rule( rule ) predecessor, successor = rule.strip.split( /\s*(?:->|→)\s*/, 2 ) self.log.debug "Parsed rule: %p -> %p" % [ predecessor, successor ] successor_set = Set.new( successor.chars ) raise "Invalid rule: predecessor %p is not in the variable set %p" % [ predecessor, self.variables ] unless self.variables.include?( predecessor ) raise "Invalid rule: successor %p contains characters not in the alphabet %p" % [ successor, self.alphabet ] unless self.alphabet.superset?( successor_set ) return predecessor, successor end
Return a Hash of tranforms that should be applied to a state during a generation.
# File lib/l_system/rules_engine.rb, line 153 def rules_as_hash unless @rules_as_hash @rules_as_hash = self.rules.each_with_object( {} ) do |rule, hash| pred, succ = self.parse_rule( rule ) hash[ pred ] = succ end self.alphabet.each do |char| @rules_as_hash[ char ] = char unless @rules_as_hash.key?( char ) end end return @rules_as_hash end