Python Programming in Context Chapter 9
Objectives To introduce functional programming style To practice writing recursive functions To introduce grammars and production rules
Recursion A self referencing solution Base case is easily solved Recursive step uses solution to try to solve smaller version of the problem Sometimes easier to see with pictures
Figure 9.1
Figure 9.2
Infinite Recursion No base case In theory this will continue to call itself forever In practice, memory will eventually be completely consumed and process will stop
Listing 9.1 def hello(): print("Hello World") hello()
Nested Squares Base Case – Draw a simple square Recursive Step – Draw a picture of recursive squares starting with a smaller side length
Figure 9.3
Listing 9.2 def drawSquare(aTurtle,side): for i in range(4): aTurtle.forward(side) aTurtle.right(90) def nestedBox(aTurtle,side): if side >= 1: drawSquare(aTurtle,side) nestedBox(aTurtle,side-5)
Recursive Tree Draw trunk Recursively draw a tree on the right Recursively draw a tree on the left Stop when the tree is sufficiently small
Listing 9.3 def tree(t,trunkLength): if trunkLength < 5: return else: t.forward(trunkLength) t.right(30) tree(t, trunkLength-15) t.left(60) tree(t, trunkLength-15) t.right(30) t.backward(trunkLength)
Sierpinski Triangle Draw triangles from triangles by connecting the midpoints of the sides Continue to do this for each newly created triangle Stop at a sufficient number of levels
Figure 9.4
Figure 9.5
Figure 9.6
Listing 9.4 def drawTriangle(t,p1,p2,p3): t.up() t.goto(p1) t.down() t.goto(p2) t.goto(p3) t.goto(p1) def midPoint(p1,p2): return ((p1[0]+p2[0])/2.0,(p1[1]+p2[1])/2.0) def sierpinski(myTurtle,p1,p2,p3,depth): if depth > 0: sierpinski(myTurtle,p1,midPoint(p1,p2),midPoint(p1,p3),depth-1,) sierpinski(myTurtle,p2,midPoint(p2,p3),midPoint(p2,p1),depth-1,) sierpinski(myTurtle,p3,midPoint(p3,p1),midPoint(p3,p2),depth-1,) else: drawTriangle(myTurtle,p1,p2,p3)
Figure 9.7
Recursive Snowflakes Koch Curve L Systems Recursive Grammers Following a sequence of instructions that are recursively generated
Figure 9.8
Figure 9.9
Figure 9.10
L System Axiom (starting symbol) Rules (substitution) Axiom A Rules A → B B → AB
Example A Axiom B (apply rule 1 to A) AB (apply rule 2 to B) BAB (apply rule 1 to A, then apply rule 2 to B) ABBAB (applyrule 2 to B, then rule 1 to A, then rule 2 to B) BABABBAB (rules applied: 1, 2, 2, 1, 2)
Listing 9.5 def drawLS(aTurtle,instructions,angle,distance): for cmd in instructions: if cmd == 'F': aTurtle.forward(distance) elif cmd == 'B': aTurtle.backward(distance) elif cmd == '+': aTurtle.right(angle) elif cmd == '-': aTurtle.left(angle) else: print('Error: %s is an unknown command'%cmd)
Listing 9.6 def applyProduction(axiom,rules,n): for i in range(n): newString = "" for ch in axiom: newString = newString + rules.get(ch,ch) axiom = newString return axiom
Listing 9.7 def drawLS(aTurtle,instructions,angle,distance): stateSaver = [] for cmd in instructions: if cmd == 'F': aTurtle.forward(distance) elif cmd == 'B': aTurtle.backward(distance) elif cmd == '+': aTurtle.right(angle) elif cmd == '-': aTurtle.left(angle) elif cmd == '[': pos = aTurtle.position() head = aTurtle.heading() stateSaver.append((pos,head)) elif cmd == ']': pos,head = stateSaver.pop() aTurtle.up() aTurtle.setposition(pos) aTurtle.setheading(head) aTurtle.down()
Listing 9.8 def lsystem(axiom,rules,depth,initialPosition,heading,angle,length): aTurtle = turtle.Turtle() win = turtle.Screen() aTurtle.up() aTurtle.setposition(initialPosition) aTurtle.down() aTurtle.setheading(heading) newRules = applyProduction(axiom,rules,depth) drawLS(aTurtle,newRules,angle,length) win.exitonclick()
Figure 9.11