Professional Documents
Culture Documents
Graphics and Functions
Graphics and Functions
1
Chapter 3 2
Graphics 2
Turtle Geometry 3
Functions 6
Loops 11
Turtle Methods 13
Bottom Up Construction 16
Main Program 17
Exercises 34
Solutions to Exercises 38
Footnotes 46
Chapter 3
Graphics and Functions
The algorithmic notation we learned in the Chapter 2 is a proper subset of the Python
language and contains only the essential constructs needed for writing workable algorithms
for a wide variety of problems. By restricting the pseudocode to a few basic instructions with
which to build technical specifications that can be implemented on a computer, we aim to
emphasize the concepts and the competency with these basic constructs.
As we have seen, a principal part of the solving problem process is describing and analyzing
the problem to formulate a solution. We do this in plain language, but it needs to be clear,
concise, and well organized in logical steps. In this phase we propose the strategy to solve
the problem; the design that contains the solution. The next phase is to transcribe this design,
to a technical specification that will facilitate the implementation of the solution on the
computer, which requires writing the algorithm. This is a difficult step for we have to
transform a plan, or design expressed in general terms to an algorithm in specific technical
terms. It requires a good dose of computational thinking and knowledge of the algorithmic
notation; the ability to turn a plain language description into variables, sequences,
expressions, conditionals and loops. Only when done correctly is the solution implemented
on the computer.
In this chapter we will add more functionality to the algorithmic notation, to allow the
solution for a wider range of problems, building on the basic constructions and concepts
with which we are now familiar, and exploring other applications that will enhance our
ability to write correct algorithms.
Graphics
Solving problems requires that we think a little different, in a more “problem oriented” way,
in small steps but without losing sight of the broad picture. Thinking computationally in
terms of decomposition, abstractions, patterns and of the concepts and constructs used by the
algorithms.
To learn this in a proper way, we need to explore. Explore the computational world, and the
mathematics that lies behind it. The most important thing about exploring is for you to do it
rather than just passively read what is written about it. So it is best that you follow in your
computer the examples and exercises that are presented, trying various alternatives on your
own so as to become proficient with the algorithmic notation and the concepts that it uses.
!3
Turtle Geometry
This is a new kind of geometry that exists only in the virtual world. Imagine that you have
control of a little object that we choose to call a “turtle”, that can move at your command on a
computer display screen, and leave a trail (that we see as a drawing) as it moves around. The
tradition of calling the display objects that make the drawings “turtles” goes back to the
1960s and we shall adopt this terminology. To activate the turtle type the following command
in the Python Shell (in the IDLE environment) at the prompt:
Nothing seems to happen, but all the computer code (instructions) needed for the turtle to
work is downloaded to your working space and the turtle is ready to accept your
instructions.
Let’s first look at the drawing space, or window. In the Shell, type the following:
>>> home()
You will see a window open, titled ‘Python Turtle Graphics’ with a black arrow head in the
center, pointing to the right. It represents the turtle. This window can be seen as a Cartesian
plane, with the center at coordinates (0,0), a horizontal x-axis at (x,0), and a vertical y-axis at
(0,y). The approximate dimensions are about 600 units on from top to bottom and from left to
right. We shall look at the exact dimension later in the chapter.
The turtle can respond to a few simple commands. Type forward(100) and you will see
the turtle move, in the direction it faces, 100 units.
>>> forward(100)
Now turn the turtle 90 degrees, to have it face north (or the top of window):
>>> left(90)
You will now have the turtle at the position shown on the drawing canvass:
!4
A back(distance) and right(angle) commands cause the opposite movements. As you can
see, forward and back change the turtle’s position, while left and right change the turtle’s
heading; that is, the direction in which the turtle points. When changing position, the turtle
may (or may not) leave a trace as we have seen; this is a line that appears on the screen. You
can control this by instructing the turtle to have the pendown() or the penup(); to draw or
not to draw.
When the drawing is finished, we want to release the window and close it. The command,
>>> done()
Notice that all commands are followed by a set of parentheses, which may optionally include
a value or a variable.
The remarkable thing is that with just these commands we can make some pretty drawings.
Here is an example:
Example 3.1
Draw a square with sides 100 units.
Analysis
A square is made by drawing a side of length x, changing direction of the turtle 90 degrees,
and repeating these two steps four times. Here is an algorithm to do it:
Algorithm
for x in [100,100,100,100]:
forward(x)
left(90)
done()
Here is the result:
!5
Notice that you could have used a while loop to draw the algorithm, or no loop at all and
simply repeat the two basic instructions (the invariant) four times. Either case would have
given the same result.
Example 3.2
Draw a pythagorean triangle using the turtle.
Analysis
In a pythagorean triangle the lengths of the sides are given by a pythagorean triple, three
integers which satisfy the Pythagorean Theorem, a2 + b2 = c2. The best known case is the 3, 4,
5 triangle. So, let’s draw a triangle with sides 3, 4 and 5. However, a move of less than 10 is
very small on the drawing canvass, so we will scale up the side lengths by a factor of 10: we
will draw a 30, 40, 50 triangle.
Algorithm
# example 3.2
# first activate the turtle
from turtle import *
How does this work? When the order to go home() is given, the turtle moves and, since the
pen is down, it will draw the line from the vertice to the center of the plane.
Functions
Turtle geometry would be boring if the turtle was restricted to only change position and
direction, but it so happens that we can teach the turtle new tricks. With a set of commands
that it already knows, it can draw a figure, learn the procedure and replicate it at will at any
time later.
For example, let’s take the set of statements from Example 3.1 that draws a square. As it is, to
have the turtle draw the same square again, we have to repeat the same set of commands:
for x in [100,100,100,100]:
forward(x)
left(90)
done()
However, by naming this procedure the turtle can remember it, and the next time we need to
draw a similar square we just call its name, as the next example shows.
Example 3.3
from turtle import *
# define a procedure to draw a square of side 100
def square():
for x in [100,100,100,100]:
forward(x)
left(90)
square()
done()
!7
To draw a square of side 100 we only have to write square() and the turtle will draw it.
But, of course, you have to define the procedure (with the def statement) before using it.
• To name the procedure we use the reserved word def with this syntax:
• The definition gives the name of the procedure followed by parentheses (), and a
colon :
• Remember that any statement ending with a colon : is always followed by a set of
indented statements.
• We place the three statements that actually draw the square inside the definition,
properly indented to indicate that they are to be executed as a block.
• Other statements, before or after the definition, are not part of the procedure and
therefore are not indented. They are placed at the same left margin position as the
definition statement def. In this case this are the from turtle import * , the
procedure call square(), an the the done() statements.
• The purpose of the def statement, and the set of statements it contains, is only to
define the procedure, or function (as we prefer to call any command that is followed by
a pair of parentheses). It does not perform any visible action. To be effective, the set of
instructions that constitute the algorithm must included within the definition of the
function, before using it.
def <name>():
<body of the function>
<other statements in the algorithm>
• Once defined, the function can be invoked anywhere, as any instruction, and as often
as needed, because the turtle has learned to use it. A function is called or invoked by
its name, function_name().
Function Arguments
The function square(), as defined above, will make the turtle draw a square with sides 100
units in length. But if we want to draw a square with a different side length we have to
redefine the function. To deal with this situation a function definition allows the possibility of
passing data to the algorithm within the function, resulting in functions with greater
versatility. For example if we can pass to square(), the length of the side, then we have a
!8
function that can draw any size square, and all we need to do is specify the specific length
when the function is called.
To use this capability, when the function is defined we include in the definition the value (or
values) that we want to pass to the function: these are called arguments and are included
within the parentheses of the name, separated by commas if there is more than one. In the
case of square(), to pass the length of the side (of the square) that we want the turtle to
draw, we use a variable name (e.g. side), and include the variable name in the definition,
like this:
Example 3.4
Draw a square of any size
def square(side):
i = 0
while i < 4:
forward(side)
left(90)
i += 0
square(75)
done()
Inside the function, the instruction that actually draws the side with a specific number of
units was changed from 100 to the variable side. When the function is called we specify the
value for side, passed it to the function, and the forward(side) instruction is executed
with the value that the variable references. In the example we pass the value as a constant (it
can be passed as either a variable, or an absolute constant), and a square of side 75 units will
be drawn. We could have passed the value as any name. Suppose x = 37.5, then we invoke
the function as:
square(x)
and a square of side 37.5 will be drawn by the turtle. The name of the argument is assigned
when the function is first defined, and that specific name is used by the code within the
function. But at call time any variable, of the same type, with a valid value can be used to
pass the data.
Example 3.5
Write a function to draw a regular polygon of n sides.
Analysis
!9
A regular polygon is a closed geometric figure in which all of its sides and angles are equal.
To draw any regular polygon we need to define the number of sides and, optionally, the
length of a side if we want the function to draw polygons of varying size. Since it is a closed
figure, to draw the polygon the turtle will rotate 360 degrees; n equal rotations, which means
that any angle will be 360/n degrees. With this information we can proceed to write the
algorithm.
Algorithm
We first write the algorithm to draw a polygon of n sides:
We want to teach the turtle to draw regular polygons, but we need to give it the number of
sides so that it can draw any regular polygon. We do this by giving it the number of sides as
an argument inside the parentheses in the definition of the function. The argument (or
arguments, because there can be several) is a written as a variable in the definition. Inside the
function, this variable name is used as an input variable, by one or several statements below
the definition.
The algorithm above is converted to a function that passes one argument, the number of
sides n_sides, to the code inside the function.
# ----- call the function with a value for the argument ----
regular_polygon(5)
done()
!10
Notice how the argument n_sides is defined, and how it is used to calculate the angle. In
this case the function is called with an argument = 5 to draw a pentagon.
—————————————
Be aware that you have to define the function first, and then invoke it with an argument of
the same type. The argument must be passed (if not, it will raise an error), and it can be a
variable or a specific value, as in this case. When calling the function the name of the variable
used is not important; any value or variable name (the same n_sides used in the definition
or any other name) may be used. The function, by the position of the argument, will assume it
is the n_sides of the original definition.
The function regular_polygon(), as it is, will draw all polygons with side 100. We would
like to make the side a variable so the turtle can draw polygons of various sizes. To do this
we need to add another argument to our function definition.
Here is how we modify the previous function to take two arguments, n_sides and length,
representing the number of sides and the length of each side, respectively. We then ask turtle
to draw two different polygons, changing the arguments. Notice how in the second polygon
we use different variable names. The function definition takes these names, and by their
position, assigns them to n_sides and length, respectively.
Example 3.6
Draw a regular polygon of any size with variable side length
# ----- call the function with a value for the argument ----
regular_polygon(7, 100)
sides = 6
size = 50
regular_polygon(sides,size)
!11
done()
Here is the output:
Loops
Turtle graphics uses loops, while and for, regularly and provides an effective mechanism
for practicing repetition commands. A useful complement to the for loop iterator is the
range() function.
Range
Now that we have had some experience with for loops using only sequences, we can
appreciate better the range function. A for loop is controlled by a sequence of elements;
more specifically by the number of elements in the sequence. That is what determines how
many iterations the for loop will make. In many instances we require a large number of
iterations, and sometimes consecutive integer values for the iterator variable. This means that
we have to create the appropriate sequence before using the for loop. The range function is
most convenient for creating such sequences. In it more general form, the function can take
three argumentes, and this is its syntax:
All arguments must be integers. The first argument start is the first value in the sequence,
and is optional. If not give, it is assumed to be cero (we say, 0 by default). The next argument
is required and gives the value where the sequence will stop, but it is not included in the
sequence. That is, the sequence generated will contain integers from the start number up to,
but not including, the stop number. The last argument is the step in which the sequence of
integers will be generated, it is optional, and its value is assumed to be 1 by default, if not
specified. Here are some examples:
Example 3.7
The range() function
!12
Why is it False? If we ask the Interpreter about range(), this is how it sees it:
>>> range(5)
range(0, 5)
It sees range(5) not as a sequence [0, 1, 2, 3, 4], but as a function that generates a
sequence on demand. Range does not create the sequence in memory when it is called. It
generates the elements of the sequence as they are needed. This is important with large
sequences because it does not store the whole sequence in memory, but only the code for
generating the integers.
If we do need the sequence as such, it can be generated with range() and then converted to a
sequence with list(), as shown below:
Exercises 3.1 will reinforce your understanding of functions and loops. Study the figure
carefully before writing the algorithm, and test your work often. It is better to detect mistakes
as soon as they are made, rather than wait until the whole algorithm is coded. Testing is a
fundamental skill that you must learn.
Here are some additional commands for the turtle that you can apply in the Exercises that
follow.
>>> setheading(angle)
setheading(angle) will set the orientation or heading of the turtle to the specified angle in
degrees. For example, setheading(90)will set the turtle to point north (upwards, or top of
!13
the window). Angles of 0, 180, 270, etc. will set the orientation to west, east, or south,
respectively.
>>> reset()
reset() will delete the turtle drawings from the screen, and place it at home() (at the center
position (0,0)), facing west (to the right of the screen), with the pen down.
>>> clear()
clear() is similar for it will delete all turtle drawings from the screen, but it does not move
the turtle and it does not change any of the current properties of the turtle, nor affects
drawings made by other turtles.
At any time, while drawing or when finished drawing, the turtle icon may be hidden from
view. To make the turtle invisible include the command,
>>> hideturtle()
When hidden, the turtle will still leave a trace if pendown() is active. To make the turtle
visible again use,
>>> showturtle()
Turtle Methods
We have seen that with a few commands we can instruct turtle to make interesting and
didactic drawings. These commands are technically known as methods. In general, a method
performs some action when invoked (much like a function), we do not know how it does it,
and usually do not care. The complete inventory of the methods and attributes available to
the turtle can be found in the documentation on line. You can access it by querying the
browser for “turtle graphics py 3” which will show the link “turtle — Turtle graphics —
Python 3.7.4 documentation".
Here is a partial list of turtle methods and attributes, including those we already know and
several new ones.
• forward(distance) moves the turtle in the direction it is facing, a distance units. The
line will be drawn even if the turtle is not visible (hidden).
!14
• backward(distance) moves the turtle backwards a “distance” in pixels, tracing a
straight line in the opposite direction at which the turtle is pointing. The line will be
drawn even if the turtle is not visible (hidden).
• left(angle) turns the turtle anticlockwise (right) by “angle”. Angles are measured in
degrees, by default.
• right(angle) turns the turtle clockwise (right) by “angle”. Angles are in degrees, by
default.
• penup() or up() raises the pen, that the turtle uses to draw, from the canvas. The
drawing turtle is a metaphor (an abstraction) in which a tiny robotic turtle holds a
“pen” (could be its tail), with which it draws by holding it down against the canvas. Of
course, if it raises it will not draw, but the turtle can still move about. By default, the
turtle starts with the pen down, using black ink.
• pendown() or down() lowers the pen so that drawing resumes when the pen is up.
If the pen is already down it has no effect.
• pensize() or width() returns the “size” or width of the pen in use if called without
an argument. When used, the argument is a positive number, and determines the
thickness of the line drawn. For example, pensize(3.5), or width(5).
• setheading(angle) sets the heading of the turtle to ‘angle’, measured in the current
setting of degrees or radians.
• position() returns the position of the turtle as a pair of coordinates (x, y) on the
cartesian plane. The coordinates are relative to the origin, which by default is at the
center of the canvas (the plane)
• home() moves the turtle to the origin (coordinates (0, 0)) and sets the heading of
the turtle to the default value (pointing right). As with goto(0,0), it will trace a line
on the canvas if the pen is down. To move the turtle to another position without
drawing a line the pen must be up.
• shape(name=None) set the turtle shape to a form with the given name, or return the
current shape name if None is given. The valid names for turtle shapes are ‘arrow’,
‘turtle’, ‘circle’, ‘square’, ‘triangle’, and ‘classic’. New shapes can be created by we are
not going to do that. See the documentation for further details.
• window_width() returns the width of the current canvas (or window), in pixels.
• stamp() stamps (i.e. prints) a copy of the turtle shape onto the canvas at its current
position, and returns its id (identification number). The stamp can later be deleted by
calling clearstamp(id).
• clear() deletes the turtle drawings from the canvas, without moving the turtle or
changing any of its attributes. It does not affect the drawings of other turtles.
• reset() deletes the turtle drawings from the screen, and places it at the home()
position, with all default attributes.
• dot(size, color) draws a circular dot with diameter size and color (a color name, in
quotes)
• circle(radius, arc) draws a circle with radius. If arc is not give, draws a full circle,
otherwise only part of the circle. arc is an angle.
• begin_fill() call this method just before drawing a shape that you want filled.
• end_fill() call the method when shape is drawn, and after calling begin_fill().
It fills the shape with the second color given in color(pen_color, fill_color), or
fillcolor().
• write(‘text’), writes text at the current turtle position. For other arguments see the
documentation.
!16
These methods are related to the Turtle Screen, so if using dot notation to invoke the
methods, they are applied to the screen name (e.g. ‘canvas’), not to the turtle name (e.g. ‘tyr’).
• bgcolor(options) returns the current background color of the Turtle Screen if called
without options. Otherwise changes the background color of the screen to the option
given. The options are the same as those used in the method color().
• title(‘title_string’) sets the title of the turtle window (or ‘canvas’) to ‘title_string’.
Try these methods and become familiar with their operation so that you can use them in your
programs. If you need addtional explanation on any of the methods, use the online help from
the Shell as in this example,
>>> help(turtle.window_height)
The dominant strategy for dealing with such computer problems is a two-phase strategy,
known as top down (analysis and) design, and bottom up construction.
In terms of the algorithm(s) that lead to the solution, you want to identify parts that can be
coded as functions and their arguments (input data), the action performed by the function
and/or the data returned (output). How are these functions related to one another, how are
they called, and when are they called.
These connections are specified in a main code (or driver code) that assembles the parts,
initializing variables, making the necessary function calls and displaying the results.
Bottom Up Construction
!17
The bottom up construction is applied to each component of the problem and usually refers to
a specific function. Functions have arguments and return (optionally) a result (data). They
always perform a specific action.
Functions are built better from the bottom up. This means that you begin by writing the basic
algorithm, probably for a specific case. The algorithm is tested, if it contains iterations (for
or while loops) the invariant is identified. Recall that the invariant is the group of statements
that execute the action that needs to be repeated. Once tested, the algorithm is converted to a
function, adding the definition, a name with arguments when these are required. The
arguments are the input data that allow the function to perform its action for various
instances. Each function is built, documented, and tested separately.
Main Program
The main program is an assemblage of the parts that constitute the solution to the problem. It
is the code that produces the final results. Necessary data is captured (if necessary), variables
are initialized, and functions are called in order, and results are shown.
The best way to illustrate the method described is with some examples.
Example 3.8
The Fibonacci Spiral
Write a computer solution to draw a Fibonacci Spiral, similar to the figure shown below.
(3) Each square contains a 90 degree arc (part of a circle of radius equal to the side of the
square), which when connected together result in the fibonacci spiral.
Bottom Up Construction
The Fibonacci Sequence
Follow carefully as we construct a function to generate the fibonacci sequence, from the
ground up, step by step.
(1) We can write directly the list of fibonacci numbers, or write a short function to generate
the sequence. We choose to write the function.
• The first two number of the fibonacci sequence (the seeds) are i and n, where i is the
initial number, 0, and n is the next number, 1.
i, n = 0, 1
• We want to generate a sequence, so start with a sequence fs that contains the first
element of the sequence we want:
fs = [1]
• To obtain any fibonacci number n we add the previous two fibonacci numbers. In
algorithmic notation this can be written as:
i, n = n, i + n
The above expression can be read as follows. Starting with the right-hand side of the
assignment:
• n is a fibonacci number, and i + n is the sum of the initial fibonacci number and
the next fibonacci number.
• These values are assigned to the left-hand side of the expression as follows: n is
assigned to i (the next fibonacci number), and the sum i + n is assigned to the next
fibonacci number n.
• The expression is equivalent to writing two separate assignment statements,
i = n
n = i + n
• To generate the sequence, we append (add to the end) the new fibonacci number n.
This can be done either with the statement fs.append(n), or using concatenation,
fs = fs + [n].
• In summary, we now have the invariant (the instructions that calculate one fibonacci
number and add it to the end of the list.
!19
i, n = n, i + n
fs.append(n)
for k in range(f):
i, n = n, i + n
fs.append(n)
• We want to use this algorithm as a function, so define the function with argument f to
create a list of f elements.
Example 3.8.1
Fibonacci sequence
def fibonacci_seq(f):
‘’’
Create list of f fibonacci numbers. Does not
include 0.
f is type int
returns list of fibonacci numbers, type list
‘’’
fs = [1]
i, n = 0, 1
for k in range(f):
i, n = n, i + n
fs.append(n)
return fs
(2) The next part we need is a function to draw squares of any size.
For this task we already have a function , developed in Example 3.4 which we reproduce
below for convenience, modified to use a for loop instead of a while loop.
Example 3.8.2
Draws a square of any size using a for loop
def square(side):
# i = 0
# while i < 4:
for i in range(4):
forward(side)
left(90)
#i += 0
!20
Test the function with the fibonacci sequence generated in Example 3.8.1. We increase the
length of the sides by a scale of 3.
Example 3.8.3
Test Example 3.8.2 with fibonacci sequence.
def fibonacci_seq(f):
'''
Create list of f fibonacci numbers. Does not include 0.
f is type int
returns list of fibonacci numbers, type list
'''
fs = [1]
i, n = 0, 1
for k in range(f):
i, n = n, i + n
fs.append(n)
return fs
def square(side):
''' draw a square with length side '''
for i in range(4):
forward(side)
left(90)
# -------- test functions ----
seq = fibonacci_seq(8)
for side in seq:
square(side*3)
done()
We have the fibonacci squares drawn, but we need to place them side by side in a tile
arrangement. Let’s see how we can do that.
Draw the first square, of size 1 (scaled by 10), and pay attention to the position and direction
of the turtle:
!21
Examining the spiral we observe that the next square, also of size 1, is drawn to the right,
starting at the top right corner of the first square, like this:
The figure shows the position of the turtle after drawing the second square of size 1. To draw
the next square, size 2, with the same function and the same starting orientation of the turtle
(positioned to draw counterclockwise), we need to place the turtle at the right lower corner
of the drawing, facing to the left, like this:
The square that follows is of size 2. When finished we want the turtle on the lower left hand
corner facing north (up), ready to draw the square of size 3.
Writing the detailed steps required to draw these squares and position the turtle with the
correct orientation we have the following code:
square(1*50)
penup()
goto(50, 50)
pendown()
right(90)
!22
square(1*50)
penup()
goto(100, 0)
pendown()
right(90)
square(2*50)
penup()
goto(0, -100)
pendown()
right(90)
Notice that the drawing follows a sequence, which is repeated for each square:
• position the turtle at the opposite vertex of the starting position and rotate 90 degrees
to the right (an instance of this opertion is highlighted above).
These two steps are the invariant in the algorithm. They have the same five statements, and
only some parameters change. The goto() statement has the coordinates of the turtle at the
“opposite vertex of the starting position”. We find these coordinates with the position()
function which returns the coordintes of the turtle at a particular position. When drawing
the square, call postion() when the turtle is at the opposite vertex of the starting position.
You need to modify the code of the square() function:
Example 3.8.4
Modified square() function that returns the position of the vertex on the diagonal
def square(side):
‘’’ draws a square and captures the position of the diagonal
vertex.
returns the coordinates of the diagonal vertex.
‘’’
for i in range(4):
forward(side)
if i == 1:
vertex = position() # store the position of the turtle
left(90)
return vertex
pos = square(40)
print(pos)
print(square(55))
done()
!23
It draws two squares and prints these coordinates:
(40.00,40.00)
(55.00,55.00)
which are the correct values.
We are ready to draw the fibonacci squares in a tiled arrangement, following the reasoning
given above. Since the first elements of the fibonacci sequence are small numbers, use a
‘scale’ to increase the dimensions of the drawing.
Example 3.8.5
Fibonacci squares in a tiled arrangement
def fibonacci_squares(fib_seq,scale):
"""
Draws a sequence of fibonacci squares from a list of
fibonacci numbers, fib_seq.
"""
for f in fib_seq:
vertex = square(f,scale)
penup()
goto(vertex)
pendown()
right(90)
Again, we test the function to verify that it tiles the squares correctly. Note the use of ‘scale’.
fib_seq = fibonacci_seq(7)
scale = 5 # scale for the drawing
# draw squares
fibonacci_squares(fib_seq,scale)
hideturtle()
done()
Finally, to draw the spiral we start at the origin and draw an arc
of a circle with the same radius as the fibonacci square, curving in a clockwise direction. We
use the circle() function (a tutle method), with the radius taken from the fibonacci sequence,
and the arc -90 degrees to get the right curvature. As a last detail, write the square size next
to each square when it is drawn, by including the following statement,
Example 3.8.6
The Fibonacci Spiral
def square(f,scale):
"""Draws a fibonacci square of side f with scale, where f is a
fibonacci number. f is type int, and scale is a number.
It captures the position of the vertex of the square
from where a segment of the spiral is drawn.
"""
for i in range(4):
forward(scale * f)
if i == 1:
vertex = position()
write(f, align="right", font=("Arial", 10, "normal"))
left(90)
return vertex
def fibonacci_squares(fib_seq,scale):
"""
Draws a sequence of fibonacci squares from a list of
fibonacci numbers fib_seq.
"""
for f in fib_seq:
# vertex has the coordinates of the vertex at the
# diagonal point
vertex = square(f,scale)
penup()
goto(vertex)
pendown()
right(90)
def fibonacci_spiral(fib_seq):
!25
"""
Draw a fibonacci spiral over the fibonacci squares.
input: fib_seq, the same fibonacci sequence used by
fibonacci_squares(...).
"""
for fn in fib_seq:
circle(scale * fn, -90)
To draw the spiral, we shall use a scale of 20 and place the origin at (145, 145):
Another example to illustrate the Top Down - Bottom Up strategy is this case of a random
walk.
Example 3.9
Turtle Random Walk
In this example we will draw a squared lined paper pattern
on the canvas and then, starting at the origin (0,0), will
make the turtle walk over the grid lines in a random way
until it touches one of the edges of the lined paper. The
figure on the right shows an example of the turtle’s random
walk on the squared lined paper:. When the walk ends,
print 1) the number of steps taken, and 2) the final position
of the turtle.
!26
(2) Moving the turtle one square in a random direction of 0, 90, 180 or 270 degrees, until
it touches a border of the graph paper.
• add up the distance moved and record the final position of the turtle when it
touches.
(3) Print total total distance walked and final position of the turtle.
Bottom Up Construction
(1) Start with the graph paper. This short function will draw n_lines of a specified
length, with a fixed space between lines.
def lines(length,space,n_lines):
for i in range(n_lines):
angle = 90 * (-1)**(i % 2)
forward(length)
penup()
left(angle)
forward(space)
pendown()
left(angle)
k = 250
s = 10
n = 20
speed(0)
hideturtle()
lines(k, s, n)
done()
To draw the graph paper we call lines()twice, the first call is to draw the horizontal lines
and the second call to draw the vertical lines. The function grid(lenght, space,
n_lines, start) draws a square grid, with same n_lines of the same length and
space between them. The starting point for the grid is at start.
!27
Example 3.9.1
Draw the grid
When finished move the turtle to the center and place a red dot at the starting position.
title("Random Walk")
pencolor("lightgray")
hideturtle()
speed(0)
hideturtle()
# draw grid
k = 500 # grid width and length
n = 51 # number of lines
s = 10 # space between lines
start = (-250, -250) # starting point of the grid
penup()
goto(start) # lower left-hand corner of grid
pendown()
grid(k, s, n, start)
penup()
home()
pendown()
pencolor("red")
dot(10,)
done()
-m/2 ≤ x ≤ m/2
and
-n/2 ≤ y ≤ n/2
where x, y are the coordinates of the position of the turtle at any time during the walk. The
following function will make the random walk, compute the distance walked and records the
position of the turtle.
Example 3.9.2
Random Walk
import random
def random_walk(m, n, s):
"""
Do a random walk over the grid.
m and n are the dimensions of the grid (m is horizontal width,
and n is the vertical height), both type int.
s is the space between the lines of the grid, type int.
returns the position of the turtle (the coordinates), and the
distance travelled.
"""
x = y = dist = 0
while abs(x) < m//2 and abs(y) < n//2:
# choose a random direction
setheading(random.choice([0, 90, 180, 270]))
forward(s)
dist += s
x, y = position()
pos = position()
return (pos, dist)
The final result is obtained with the following code that uses the functions defined above:
Example 3.10
Draw at least three flowers of different colors, as shown in the figure.
• draw a petal
• draw stem
Bottom Up Construction
(1) Start with the petals
Example 3.10.1
The petals
Example 3.10.2
A flower with n petals
"""
for i in range(n):
begin_fill()
petal(r, angle)
end_fill()
left(360 / n)
The color is specified before calling the flower_with_petals() function. Test it.
The finished flower has a color and red dot in the center.
Example 3.10.3
The finished flower
Test the function. The fill color is defined before calling the function.
To draw the flower stem, begin at a position at the bottom of the screen, for example (0,-200).
Stems are drawn “DarkGreen” color as a circle(radius, arc) with long radius and small arc.
The following functions draw the stem and the flower at the end of the stem. The code is self
explanatory.
Example 3.10.4
The flower on a stem
(thick).
Leaves the pen up
"""
color('DarkGreen')
pensize(thick)
setheading(90)
circle(radius, angle)
penup()
For the complete solution we connect the previous functions in a main program as follows:
# initial settings
bgcolor('black')
n = 7 # number of petals in a flower
r = 50 # radius of petal
a = 90 # angle of petal
speed(0)
# Draw flowers with stem
flower_on_stem(1200, 20, 7, "magenta")
flower_on_stem(-700, 30, 5, "blue")
flower_on_stem(-1500, 10, 6, “yellow")
flower_on_stem(500, 30, 5, "blue")
hideturtle()
mainloop()
Exercises
Exercise #3.1
Draw an arrangement of 8 squares (of side 100) by rotating the turtle 45 degrees to the left
after drawing a square. The composite drawing is shown in the figure below.
5. Draw the last figure. The basis for this drawing is the
figure in (1), followed by right(10) and
forward(50). Repeat as many times as necessary to
make the closed figure.
!35
Exercise 3.3
Open the file xxx.py and run the script. You will see a set of nine dots on the screen. The
center dot is at the center of the screen, (0,0). The corner dots are at positions (50,50) , (-50,50),
(-50,50) and (-50,50). The other dots are 50 units from the center.
The object of the puzzle is to connect the dots using only four straight lines, without lifting
the pen. Describe first the solution in words (plain language), and then write the algorithm in
algorithmic notation to draw the solution with the turtle.
Exercise 3.4
1. Write an algorithm to draw the figure below. The drawing should be very much like the
one shown, in the center of the screen, with the same inclination, and a small separation
between lines.
2. Making a small variation to the algorithm in part (1), draw the spiral below.
!36
3. Convert the algorithm in part (2) to a function that can draw either figure, from part (1)
or part (2). Test the function.
4. Modify the function in part (3) to take a new argument that will add color to the figures it
draws. Test the function.
Exercise 3.5
Draw the following figures.
Exercise 3.6
Write functions to do basic linear algebra operations:
Solutions to Exercises
Exercise #3.1
Draw the figure shown:
Solution
The figure is a composite drawing of 8 square made by drawing a base square from the
center, rotating 45 degrees (left or right) and drawing the same square, and repeating the
pattern 8 times. We use a function for the basic square, and for loops with range iterator.
Algorithm
def square():
'''draw a square of side 100'''
for i in range(4):
forward(100)
left(90)
Algorithm
2. Using the function defined in (1) draw the figure shown on the
right.
Algorithm
def four_things():
'''link four things in a closed figure'''
for i in range(4):
thing()
3. Draw the last figure. The basis for this drawing is the
figure in (1), followed by right(10) and
forward(50).
!40
Algorithm
setheading(90)
for i in range(9):
thing()
right(10)
forward(50)
hideturtle()
done()
def thing():
'''draw a thing'''
forward(100)
right(90)
forward(100)
right(90)
forward(50)
right(90)
forward(50)
right(90)
forward(100)
right(90)
forward(25)
right(90)
forward(25)
right(90)
forward(50)
def four_things():
'''link four things in a closed figure'''
for i in range(4):
thing()
thing()
input("press enter to continue ...")
# part 3
reset()
setheading(90)
four_things()
input("press enter to continue ...")
# part 4
reset()
setheading(90)
for i in range(9):
thing()
right(10)
forward(50)
hideturtle()
done()
Notice the use of setheading() to set the direction of the turtle before starting a drawing,
of input() to interrupt the execution before drawing the next figure, and reset() to clear
the screen and place the turtle at the starting point, before the next drawing.
Exercise 3.3
To connect the dots you have to use lateral thinking. It is impossible to do it with four lines if
the lines are drawn within the perimeter of the square suggested by the dots, but nothing
says that the lines must be within that square. Below is the algorithm that draws the four
lines. The functions draw the dots on the screen. The code below the functions draws the
lines.
Algorithm
def nine_dots():
'''
Draw nine dots on a square centered at (0,0)
'''
for x in [-50, 0, 50]:
!42
showturtle()
penup()
goto(100, -100)
pendown()
pencolor('blue')
goto(-50, 50)
goto(-50, -100)
goto(100, 50)
goto(-50, 50)
hideturtle()
done()
Exercise #3.10
(1) Write the algorithm for the selection sort.
(2) Implement the algorithm in pseudocode.
(3) Test the algorithm by sorting in ascending order the sequence 6, 2, 9, 5, 7, 1, 8, 4, 3, 0.
Solution
(1) Analysis and description of how to do a selection sort:
!43
A selection sort repeatedly finds the smallest number in the unsorted part of the sequence
and places it at the beginning. To do this you need two sequences: 1) the unsorted
sequence, and 2) a sequence which holds the sorted elements. In each iteration, the
smallest number (considering the sort is in ascending order) is moved from the unsorted
sequence (1) to the other sequence (2).
Let’s suppose the input sequence is [3, 2, 5, 1]. The objective is to arrange the sequence in
ascending order → [1, 2, 3, 5]
Step 0. Start with two sequences, seq = [3, 2, 5, 1], and sorted_seq = [].
Step 1. Iterate over seq and find smallest element, call it min (min = 1)
Step 2. Append (i.e., move to the end of the sequence) min to sorted_seq ! [1]
Step 4. Iterate over seq and find the smallest element, min = 2
Step 7. Iterate over seq and find the smallest element, min = 3
Step 10. Iterate over seq and find the smallest element, min = 5
Step 13. seq has no more elements. Procedure terminates. The sorted sequence is
sorted_seq ! [1, 2, 3, 5]
# selection sort
seq = [33, 21, 15, 17, 11, 44, 37, 50, 61, 18]
#seq = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print('starting sequence', seq)
starting sequence [33, 21, 15, 17, 11, 44, 37, 50, 61, 18]
sorted [11, 15, 17, 18, 21, 33, 37, 44, 50, 61]
—————————————————-
!45
!46
Footnotes
[1] Example from Turtle Geometry — The Computer as a Medium for Exploring Mathematics, by Harold Abelson and Andrea A.
diSessa, The MIT Press, Cambridge, Mass., 1980, p.9
[2] Use HTML color codes. Search with a browser for “HTML color codes”.
!47
Example
Problem
Write a function that can draw any regular multicolor polygon.
Bottom Up Construction
(1) Let’s begin by drawing a simple square. The code that follows will do that.
Modify the code to draw a pentagon. Since the turtle has to turn 360 to draw the whole
figure, it needs to rotate 360/5 degrees for each angle (five vertices, each on an angle of 360/5
degrees, give a total rotation of 5*360/5 = 360 degrees).
for n in range(5):
forward(100)
left(360/5)
done()
!48
The two statements, forward() and left(), are the invariant which is repeated n times
to draw a polygon of n sides. The essential data is the number of sides, which determines the
angle at each vertex and the number of iterations.
(2) The second step is to convert the specific code above to a function that will draw any
regular polygon of n sides.
def polygon(n):
''' draws a regular polygon of n sides '''
angle = 360 / n
for n in range(n):
forward(100)
left(angle)
This function will draw any regular polygon, from an equilateral triangle to an n-gon, where
n is a large integer. However, for n > 10 part of the drawing will be outside the screen. That is
because the side is 100 units, so if you want to draw a 17-gon figure, you need to scale down
the drawing. You can modify the function polygon() to take another argument, the scale of
the drawing, to “zoom out” (or in) and be able to fit the figure in the screen.
The scale is a positive real number (float). The code below is modified to take a scale.
polygon(5)
done()