Lab 8: Recursion Due: 11:59 PM on 2020-04-23

This lab has two parts, “Recursion on lists and strings”, and “Koch Curve”, both of which should be implemented in the same file. The sections are described separately below.

Recursion on lists and strings

Having now discovered recursion, you’ve decided to become a recursion purist and not write any functions that use loops.

To get started, let’s re-implement some existing list and string functions recursively. What we’re trying to do here is get used to designing recursive solutions – we’re asking you to ignore the built-in already-defined functions and methods you’ve been using, and design your own recursive versions. (Just for practice with recursion, not because these are better!) So don’t use built-in functions or any other extraneous functions that get around the heart of the problem.

In your Python file implement the following functions using recursion. Your functions should return values and should not modify their parameters.

Here are some example problems and their solutions

  1. A recursive function named length that takes a list as a parameter and returns the length of the list. Your function may not use the len function (Hint: to see if a list has a length of 0, check if it equals []) For example:
    >>> length([20, 10, 35, 50, 17])
    5
    >>> length([])
    0
    
  2. A recursive function named rec_max that takes a list as a parameter and returns the largest value in the list. You may assume that the list has at least one entry in it and all types in the list are comparable without conversion, i.e., the list won’t be a mix of integers and strings (and, of course, you may not use the max function). You can use the len function. For example:
    >>> rec_max([20, 10,35, 50, 17]) 
    50 
    >>> rec_max([25]) 
    25 
    
  3. A recursive function named replace that takes as parameters three strings, and replaces in the first string, all instances of the second string with the third string. That is, replace(text, old_substr, new_substr) should replace all instances of old_substr in text with new_substr. For example:
    >>> replace("abracadabra", "a", "z")
    'zbrzczdzbrz'
    >>> replace("one fish, two fish, red fish, blue fish", "fish", "bird")
    'one bird, two bird, red bird, blue bird'
    >>> replace("one fish, two fish, red fish, blue fish", " fish", "")
    'one, two, red, blue'
    
  4. A recursive function named avoids that takes as parameters two strings, and checks whether the first string avoids using all characters in the second string. That is, avoids(word, letters) should return True if word contains none of the characters in letters and should return False if there is any overlap.
    >>> avoids('geronimo', 'abc')
    True
    >>> avoids('banana', 'abc')
    False
    >>> avoids('banana', '')
    True
    >>> avoids('', 'zebra')
    False
    

Koch Curve

Write a recursive function draw_koch(length, generation) that draws a shape called the Koch Curve. The Koch curve is a fractal – a shape that is self-similar, that is, it can be decomposed into smaller versions of the same shape.

Many of the techniques that we use to generate fractals computationally rely on the repetition of a set of steps, so we tend to talk about generations, which are the number of iterations that we used to produce the drawing. The Koch curve is a fairly simple one, and we can see its structure most clearly, by looking at how it changes from one generation to the next.

The starting place (generation 0) is a straight line.

lab8_koch0.png

For the first generation, we cut the line into thirds and replace the middle segment with two segments of the same length, forming two sides of an equilateral triangle.

lab8_koch1.png

The second generation is formed by applying this same process to every line in generation 1.

lab8_koch2.png

Further generations are formed by repeating this process, taking each line, breaking it into thirds and replacing the middle segment with a bump. Conceptually, if you take this out to infinity, you will have a very curious mathematical phenomenon – an infinitely long line between two fixed points a finite distance apart that also occupies a finite area. In practical terms, however, when the length of the individual lines becomes 1 pixel long, that is pretty much as small as we can draw.

lab8_koch3.png

To actually draw the shape, of course, we won't draw a line and then go back and remove a piece. Instead, we start conceptually with the highest generation of the fractal first. If you think about a generation 2 curve, it is really made up of four generation 1 curves that are each 1/3 the length of the generation 2 curve. But each of those generation 1 curves are made up of generation 0 curves 1/3 of that length. What that means is that we don’t actually draw any of the higher generation curves, the only thing we draw is a whole bunch of generation 0 curves (straight lines!) in different locations.

Writing the function

When you’re done, create a screen capture of your program output for draw_koch(400, 4) along with any additional drawings you did for creativity. (See the When you’re done section below for a reminder of how to capture a screenshot of a window.)

Creativity points

You may earn up to 2 creativity points on this assignment. Below are some ideas, but you may incorporate your own if you’d like. Make sure to document your extra point additions in comments at the top of the file.

When you’re done

Make sure that your program is properly documented:

In addition, make sure that you’ve used good coding style (including meaningful variable names, constants where relevant, vertical white space, etc.). Invoke your program code from within the __main__ conditional, so if your code were imported as a module nothing would happen. For this lab, when run your program should only draw the Koch curve (but your file should also contain the “Warming up” functions and any additional ones you write for creativity).

Submit your program and screenshot via Gradescope. Your program file must be named lab8_recursion.py and your screenshot lab8_screenshot.png.

To take a screenshot of the drawing window:

Mac: Press command+shift+4. Then hit the spacebar (on a mac), doing so will change the crosshairs into a camera to screenshot a specific window. If you then click on the window where your picture is drawn, an image file will be saved on your desktop entitled “Screen shot…”. You can double-click on this file to make sure it worked.

PC: You can use the “Snipping Tool”. Save your image in png format on the desktop.

Make sure you submit both your code and your image at the same time. You can submit multiple times, with only the most recent submission graded. Note that the tests performed by Gradescope are limited. Passing all of the visible tests does not guarantee that your submission correctly satisfies all of the requirements of the assignment.

Grading

Feature Points
Warmup
length 3
rec_max 4
replace 4
avoids 3
Koch curve
draw_koch 4
Generates Koch curve on run 2
Comments, style 3
Creativity points 2
Total 25

Turtle reference

Here are the most important commands (more can be found in the online documentation.) Recall that all of these must be prefaced with turtle.

forward(distance)
Move the turtle forward by the specified distance in the direction it is facing.
backward(distance)
Move the turtle backwards by the specified distance in the opposite direction to where it is facing.
right(angle)
Turn the turtle to its right by the specified angle. Note that this can be any angle, not the four cardinal directions we had with LightBot.
left(angle)
Turn the turtle to its left by the specified angle.
goto(x, y)
This drives the turtle immediately to the specified location without changing its orientation.
down()
Put the pen down so that the movement of the turtle leaves a track.
up()
Pick the pen up so that there are no tracks when the turtle moves.
pencolor(colorstring)
Change the color of the pen that the turtle is using. This can be a string such as 'red', 'yellow', 'blue', etc. Of course, you have to pick a valid color name.
fillcolor(colorstring)
When this is set, the turtle will try to "fill in" any closed shapes that you draw with the given color.
begin_fill()
Call this before starting to draw a filled shape.
end_fill()
Call this function when you have finished drawing a shape that you want to be filled. This tells the turtle the shape is done and that it can try and fill it in.
tracer(state)
Turn on or off watching the turtle trace out the shapes. This is useful when you are trying to draw complex shapes and don't want to wait. Pass in either True or False to turn the tracing on or off.
update()
If you turn off tracing, you should can use this function to get everything the turtle has drawn so far to appear.
window_width()
Returns the current width of the turtle window.
window_height()
Returns the current height of the current turtle window.