Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

(Python!) A Lindenmayer system (L-system) is a type of formal grammar (a set of

ID: 3575201 • Letter: #

Question

(Python!)

A Lindenmayer system (L-system) is a type of formal grammar (a set of rules for constructing strings of characters).

It can be used in conjunction with turtle graphics to recursively construct a fractal pattern that the turtle can then draw onscreen.

Our patterns will contain multiple symbols, but the turtle will only respond to three:

• F = move forward a fixed distance • + = turn right by a fixed angle
• -= turn left by a fixed angle

All other symbols are ignored. For example, given the pattern F-F++F-F, a distance value of 10 pixels, and an angle of 60 degrees, the turtle would produce a drawing like the following:

Likewise, if we expand the pattern to F-F++F-F++F-F++F-F++F-F++F-F and increase the forward distance to 20, we get:

1. Start by defining a Python function with the following header:

def drawLSystem (string, angle, distance)

This function should process string character-by-character, moving the turtle as specified

previously. Incorporate this function into a full program that uses textinput() and numinput() to read in the pattern,

turn angle,and forward distance from the user, and then draws the resulting L-system onscreen.

2. L-system patterns can become very long and complex, and it can be tedious to type them in.

Instead, we can write code to generate them recursively. To generate a pattern, we need three things:

• a starting string (called the seed)
• a set of production rules
• a recursion depth (the number of times to (re)apply the production rules)

A production rule replaces one character with a sequence of different characters. For example, the rule:

X ! X-YF

replaces every occurrence of X with the character sequence X-YF (yes, this means that there's still an X in the original string). So if we began with the string FX, after one round of replacement, we would have FX-YF. Applying the production rule again, we would get the string FX-YF-YF, and so on. By varying the production rules and/or the seed string, we can generate very elaborate patterns.

As an example, consider the production rule set

X ! X-YF
Y ! FX+Y

with the seed FX and a recursion depth of 10. 10 rounds
of applying these replacement rules will lead to the final
pattern, which looks like the image to the right when
drawn (with a turn angle of 90 degrees and a forward
distance of 10 pixels).2 This is the famous dragon curve
fractal.

Add a function with the following header to your program
from the previous step:

def deriveLSystem (seed, productions,
depth)

where seed is the starting string. productions is a
dictionary where the keys are characters to replace, and
the values are the replacement strings. depth is the
current recursion depth.

This function works as follows: if the depth is less than or equal to 0, return the current seed string. Otherwise, create a new, empty string. For each character in the seed, if it's present in the productions dictionary, add its replacement to the new string; otherwise, add the character directly to the new string. When this loop ends, return the result of calling deriveLSystem() with the new string as the seed and a recursion depth of 1 less than the current level.


Update your program from the previous step to prompt the user for a seed string, a sequence of production rules, and a recursion depth. For the production rules, start by prompting the user to enter the number of production rules. Then read that many pairs of strings (one for the target character, one for the replacement) into a dictionary. Pass these values to deriveLSystem() to generate a pattern for drawLSystem().

Entering the production rules manually is tedious. Modify your program so that it reads the production rules from a (user-specified) text file instead. Each production rule should span two lines: the first line contains (only) the symbol to be replaced, and the second line should contain the replacement symbols. For example, the rule file for the dragon curve fractal above would have the contents:

X X-YF Y FX+Y

Your code may assume that the input file is always well-formed (i.e., it always contains an even number of lines).

Appendix: Dragon Curve Fractal Pattern (recursive depth: 10)

The following string draws a dragon curve fractal with a recursion depth of 10.

Explanation / Answer

main.py


from turtle import *

bob = Turtle()
screen = bob.getscreen()

productiondict = {}

pattern = screen.textinput("Enter Seed String", "Enter the seed string: ")

#This is for the regular project
"""numrules = screen.numinput("Enter Number of Rules", "Enter the amount of production rules: ")

for rule in range(int(numrules)):
targetchar = screen.textinput("Enter Target Character", "Enter the target character: ")
replacement = screen.textinput("Enter Replacement", "Enter the replacement: ")
productiondict[targetchar] = replacement

if numrules > 0:
numrecursion = screen.numinput("Enter Recursion Depth", "Enter the recursion depth: ")
else:
numrecursion = 0"""


#EXTRA CREDIT:
inputFile = open('test.txt')
text = inputFile.readlines()
  
keys = text[::2]
values = text[1::2]
  
for key in keys:
productiondict[key] = values[keys.index(key)]
  
inputFile.close()
  
numrecursion = screen.numinput("Enter Recursion Depth", "Enter the recursion depth: ")

dist = screen.numinput("Enter Distance", "Enter the fixed distance: ")
ang = screen.numinput("Enter Angle", "Enter the fixed angle: ")


  
def deriveLSystem(seed, productions, depth):
global bob
if depth <= 0:
return seed
else:
newPattern = ''
for char in seed:
#
char = (char + ' ')
if char in productions:
newPattern = (newPattern + productions[char])
else:
newPattern = (newPattern + char)
return deriveLSystem(newPattern, productions, depth - 1)

def drawLSystem(string, angle, distance):
global bob
bob.pendown()
speed(0)
for command in string:
if command == 'F':
bob.forward(distance)
elif command == '-':
bob.left(angle)
elif command == '+':
bob.right(angle)
else:
print ('null')

  
  
pattern = deriveLSystem(pattern, productiondict, numrecursion)
drawLSystem(pattern, ang, dist)

===========================================================================