@extends('template')
@section('title')
Lab 11, Part 4: Fruitful recursion w/ Turtle graphics
@stop
@section('content')
# Lab 11, Part 4: Fruitful recursion w/ Turtle graphics
## Task 1. row
In last week's lab, we designed recursive Turtle functions that would draw a pattern a given number of times.
For example, when we invoked `row(3, 50)` it would draw **3** squares.
To make things more challenging, let's pretend the Turtle has a limited supply of ink. Instead of designing our function so that it repeats the design *X* number of times, let's limit it by how much “ink” is left.
Each pixel travelled represents a “drop of ink”. E.g. if the turtle moves `fd(30)` that's 30 hypothetical drops of ink. Thus, to complete a square, it would require 120 drops of ink (30 * 4).
In addition to limiting the distance travelled, we also want to find out **how many squares were drawn** with the given limit. I.e. we want to make the row function fruitful.
The following is the solution to this function. **Do not copy this code or run it in Canopy yet**.
```py
def row(inkSupply, size):
inkNeededForASquare = size * 4
# Not enough distance left to draw another square
if inkNeededForASquare > inkSupply:
return 0
else:
# Draw a single square
for i in range(4):
fd(size)
lt(90)
# Setup to draw next square
fd(size)
# Recursion
squareCount = row(inkSupply - inkNeededForASquare, size)
return squareCount + 1
```
Given the above function, your task is to sketch function call frames on the [provided worksheet](/content/labs/lab11/images/worksheet.pdf) for the following example invocations:
Example 1 to be drawn by Partner A:
```py
print row(300, 30) # ???
```
Example 2 to be drawn by Partner B:
```py
print row(60, 10) # ???
```
### Test your answers
Once your sketches are complete, paste the `row` function and invocations into your `lab11/part4.py` file and compare the computer's results against your own.
## Task 2. rowImproved
In this next task, we want to create an improved version of the row function that instead of just returning a single value (`squareCount`) it **returns a tuple** indicating how many squares were drawn *and* the total distance travelled by the Turtle/cursor.
__Capturing tuples returned from a function__
In order to complete this task, study the following example that demonstrates a function that returns a tuple...
```py
def pad(x, y, padding):
return x + padding, y + padding
```
Given the above code, make predictions of what the following print statements would produce:
```py
x, y = pad(300, 200, 10)
print x # ???
print y # ???
```
Run your code in Canopy to check your predictions. Note how the function `pad` returns a tuple. Because of this, we can capture its results in a tuple: `x, y = pad(300, 200, 10)`.
Once you understand the above code, copy and complete the following `rowImproved` function in your `lab11/part4.py` file:
```py
def rowImproved(inkSupply, size):
squareDistance = size * 4
# Not enough distance left to draw another square
if squareDistance > inkSupply:
return 0, 0
else:
# Draw a single square
for i in range(4):
fd(size)
lt(90)
# Setup to draw next square
fd(size)
# Recursion
??? = rowImproved(inkSupply - squareDistance, size)
return ???
```
Example invocations with expected results:
```py
print rowImproved(300, 30) # (2, 240)
print rowImproved(60, 10) # (1, 40)
```
__Important observation about the above function:__ Note how the base case also needed to return a tuple, `0,0`. It's essential that the value type returned by the base case is consistent with what is returned in the recursive case.
## Task 3. nestedSquares
Using the skills applied in Task 1 and 2, write a fruitful recursive function called `nestedSquares` returns a drawing of nested squares as shown in the examples below.
Parameters:
1. The **size** (length) of the square to be drawn
2. The **shrink factor** of the successive squares to be drawn
3. The **minimum sidelength** of a square; boxes will only draw a square if the side is greater than this minimum sidelength
4. The **color** of the Turtle's pen
Before writing any code, skim through the following examples and read the **hints** that follow.
#### Example A.
```py
nestedSquares(400, 0.2, 100, 'blue')
```
1 square, 1600 length (`400 * 4 sides = 1600`)
No more squares drawn because `400 * 0.2 = 80`, and 80 is less than the min sidelength of 100.
#### Example B.
`nestedSquares(400, 0.4, 100, 'magenta')`
2 squares, 2240 total length
```xml
1600 largest square (400 * 4 sides)
+ 640 small square (160 * 4 sides)
=====
2240 total length
```
#### Example C.
`nestedSquares(400, 0.75, 100, 'black')`
5 squares, 4881.25 total length
```xml
1600 (400 * 4 sides)
+ 1200 (300 * 4 sides)
+ 900 (225 * 4 sides)
+ 675 (168.75 * 4 sides)
+ 506.25 (126.5625 * 4 sides)
=========
4881.25 total length
```
#### Example D.
`nestedSquares(100, 0.8, 20, 'red')`
8 squares, 1664.45568 total length
```xml
400 (100 * 4 sides)
+ 320 (80 * 4 sides)
+ 256 (64 * 4 sides)
+ 204.8 (51.2 * 4 sides)
+ 163.84 (40.96 * 4 sides)
+ 131.072 (32.768 * 4 sides)
+ 104.8576 (26.2144 * 4 sides)
+ 83.88608 (20.97152 * 4 sides)
===========
1,664.45568 total length
```
### Hints
1. First, write the recursive function to produce the picture of nested squares. Relevant things to think about:
- When does the recursion end? Which parameter(s) determine if it is the base case?
- Handle the recursive case: draw one square and let recursion draw the remaining squares.
- Adjust the relevant parameters in the recursive call to ensure that the problem gets smaller each time.
2. After the above works, *then* add in the fruitful **counting of squares** only. You will need a variable to keep track of the square count, and you will need to return that value.
3. After the counting of squares works, *then* add the fruitful **sum of all the lengths** drawn. Each time the Turtle moves forward, keep track of that “mileage”.
There are hints in [Helpful Hints and Diagrams](/labs/lab11/hints) (see Table of Contents below), in particular, this [Turtle Hints diagram](/content/labs/lab11/hints/turtle-squares-design-patterns.png) may be helpful.
### Argh! My function doesn't work! Help!
Try some of these debugging tips: