Source code for serge.blocks.lsystem
"""Implements an L-System generator
"""
import random
[docs]class LSystem(object):
"""Implements an L-System generator"""
def __init__(self):
"""Initialise the LSystem"""
self.rules = []
self._steps = 0
self.setAxiom(None)
self.reset()
[docs] def setAxiom(self, axiom):
"""Set the axiom"""
self.axiom = axiom
if self._steps == 0:
self.reset()
[docs] def getState(self):
"""Return the current state"""
return self.state
[docs] def reset(self):
"""Reset the generator"""
self.state = self.axiom
[docs] def addRule(self, rule):
"""Add a rule to the system"""
self.rules.append(rule)
[docs] def addRules(self, rules):
"""Add multiple rules to the system"""
for rule in rules:
self.addRule(rule)
[docs] def doStep(self):
"""Step the generation by one"""
self._steps += 1
new_state = ''
state = self.getState()
cursor = 0
#
while cursor < len(state):
for rule in self.rules:
production, cursor_offset = rule.process(state[cursor:])
if production:
#
# This rule matched, so move on and try all the rules again
new_state += production
cursor += cursor_offset
break
else:
#
# Nothing matched so move on to the next character
new_state += state[cursor]
cursor += 1
#
self.state = new_state
[docs] def doSteps(self, number):
"""Do a number of steps all at once"""
for i in range(number):
self.doStep()
[docs]class Rule(object):
"""A rule for the L-System"""
def __init__(self, predecessor, successor, probability=1.0):
"""Initialise the Rule"""
self.predecessor = predecessor
self.successor = successor
self.probability = probability
[docs] def process(self, state):
"""Process the state
If we match then return the pattern we generate and the length of the state that we consumed.
If we do not match then return nothing and a zero cursor offset.
"""
if state.startswith(self.predecessor) and random.random() <= self.probability:
return self.successor, len(self.predecessor)
else:
return '', 0