Lindenmayer System Translator in Python

According to the third question of a computer science homework, it is about Lindenmayer System Translator. Lindenmayer system aka L-system is a formal grammar for modeling the growth process of plant development. In fact, it is very easy to implement L-system as long as we understand the grammar. In Python, implementing L-system is very very easy.

Since the behavior of L-system is very similar to Logo and Python already has built-in Turtle module for a while, below code will use the Turtle module as a backend.

#!/usr/bin/env python
 
import turtle
 
class Turtle:
    def __init__(self,**kw):
        self.axiom = kw.get('axiom','B')
        self.rules = kw.get('rules',[])
        self.angle = kw.get('angle',20)
        self.initial_length = kw.get('initial_length',20)
        self.speed = kw.get('speed','normal')
        self.state = []
 
    def substitute(self,s,depth):
        for i in range(depth):
            for src,dest in self.rules:
                s = s.replace(src,dest)
        return s
 
    def save_state(self):
        self.state.append((turtle.position(),turtle.heading(),self.current_length))
 
    def restore_state(self):
        pos,angle,length = self.state.pop()
        turtle.up()
        turtle.goto(pos)
        turtle.setheading(angle)
        turtle.down()
        self.current_length = length
 
    def handle_cmd(self,c):
        if c == 'B':
            pass
        elif c == 'F':
            turtle.forward(self.current_length)
        elif c == 'G':
            turtle.up()
            turtle.forward(self.current_length)
            turtle.down()
        elif c == '+':
            turtle.right(self.angle)
        elif c == '-':
            turtle.left(self.angle)
        elif c == '[':
            self.save_state()
        elif c == ']':
            self.restore_state()
        elif c == '|':
            self.current_length = int(self.current_length*0.65)
            turtle.forward(self.current_length)
 
    def interpret(self,s):
        self.current_length = self.initial_length
        for c in s:
            self.handle_cmd(c)
 
    def run(self,depth=1):
        turtle.reset()
        turtle.setheading(90)
        turtle.speed(self.speed)
        s = self.substitute(self.axiom,depth)
        print s
        self.interpret(s)
        turtle.done()
 
tree = {
    'axiom': 'B',
    'rules': [('B','F[-B]+B'),('F','FF')],
    'angle': 20,
    'initial_length': 5,
    'speed': 'fastest',
}
 
tree2 = {
    'axiom': 'F',
    'rules': [('F','|[-F]|[+F]F'),],
    'angle': 25,
    'initial_length': 150,
    'speed': 'fastest',
}
 
import sys
depth = int(sys.argv[1])
t = Turtle(**tree2)
t.run(depth)

Tags: , , , , ,

Reply