Another lovely programming exercise. I took the task one step further and created an interactive explorer of variants of the Koch curve. Some of them are very interesting. 
It should be easy to expand it to work with more complicated L-systems.
import pygame
import os
import time
import math
def rot(v, a):
sa = math.sin(a)
ca = math.cos(a)
return (v[0] * ca - v[1] * sa, v[0] * sa + v[1] * ca)
def vsum(x, y):
return (x[0] + y[0], x[1] + y[1])
def process(rule, point, length, angle, level, max_level, surface, color = (0, 0, 0)):
if level == max_level:
new_point = vsum(point, rot((length, 0), angle))
pygame.draw.aaline(surface, color, point, new_point)
return new_point, angle
s = rule[1]
new_length = length / rule[3]
if level == 0:
s = rule[0]
new_length = length
for ch in s:
if ch == '+':
angle += rule[2]
elif ch == '-':
angle -= rule[2]
else:
point, angle = process(rule, point, new_length, angle, level + 1, max_level, surface)
return point, angle
# math
start_point = (120, 100)
len0 = 300
start_angle = 0.0
systems = [
("F++F++F", "F-F++F-F", 2 * math.pi / 360.0 * 60.0, 3),
("F+F+F+F", "F-F+F+F-F", 2 * math.pi / 360.0 * 90.0, 3),
("F+F+F+F+F", "F-F+F+F-F", 2 * math.pi / 360.0 * 72.0, 3.62),
("F+F+F+F", "F-F+F+F-", 2 * math.pi / 360.0 * 90.0, 2),
("F++F++F", "-F++FF--F+", 2 * math.pi / 360.0 * 60.0, 2)
]
system_id = 0
# pygame boilerplate code
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()
mysurf = pygame.Surface((640, 480), depth=32)
myrect = mysurf.get_rect()
clock = pygame.time.Clock()
running = True
level = 1
try:
screen = pygame.display.set_mode((640, 480))
pygame.display.flip()
mysurf.fill((255, 255, 255))
process(systems[system_id], start_point, len0, start_angle, 0, level, mysurf)
while running:
clock.tick(100)
changed = False
for evt in pygame.event.get():
if evt.type == pygame.KEYDOWN and evt.key == pygame.K_ESCAPE or \
evt.type == pygame.QUIT:
running = False
break
if evt.type == pygame.KEYDOWN:
if evt.key == pygame.K_UP:
level += 1
changed = True
if evt.key == pygame.K_DOWN and level > 1:
level -= 1
changed = True
if evt.key == pygame.K_RIGHT:
system_id = (system_id + 1) % len(systems)
changed = True
if evt.key == pygame.K_LEFT:
system_id = (system_id + len(systems) - 1) % len(systems)
changed = True
if evt.key == pygame.K_PAGEUP:
len0 *= 2
changed = True
if evt.key == pygame.K_PAGEDOWN:
len0 /= 2
changed = True
if changed:
mysurf.fill((255, 255, 255))
process(systems[system_id], start_point, len0, start_angle, 0, level, mysurf)
screen.blit(mysurf, (0, 0))
pygame.display.flip()
finally:
pygame.quit()