Our goal is to create a new function
star, so that
star 12, blue
draws a blue twelve-pointed star.
Introduction to Functions
Here is the most important concept in all of programming:
A function is a miniature program. In CoffeeScript,
a function is written with an arrow
as two symbols next to each other (the minus and
the greater-than) like this:
(input) -> something to do
Writing and Naming Functions
A function that advances the turtle by ten times a distance is
(x) -> fd 10 * x
Name a function like any variable,
scoot = (x) -> fd 10 * x
After the definition, we can write
scoot 7 or
scoot 5 + 2.
In other words,
scoot can be used just
like predefined functions like
Functions can be long.
This code defines a
using indented lines after the
star = (n, k) -> # define a function star with two inputs and code to follow: pen k # use the chosen color. for [1..n] # repeat the following n times: fd 100 # move forward. rt 2 * 360 / n # turn right using a magic star formula. speed 10 # draw fast! star 7, red # use our newly-defined function!
starfunction, and save it as "star1". Some tips:
star = ...will not run it yet. To run it you must use it:
star 7, red.
starfunction with different numbers, and note the outcomes below:
Debugging the Algorithm
There is a problem with
star whenever we ask for
an even number of points:
star = (n, k) -> pen k for [1..n] fd 100 rt 2 * 360 / n speed 10 star 8, red
What causes the bug?
The problem is in the "magic" formula
2 * 360 / n.
To understand, read on.
The Geometry of Stars
Drawing a star is similar to drawing
a regular polygon. After the turtle has
gone all the way around all
corners, it will come back to where it
started, facing the same direction it started.
The difference between a star and a polygon is its winding number: In a polygon, all the turns total up to 360° because each of the n turns is (360/n)°. So the turtle winds once around the center: its "winding number" is 1. In a star, the turtle turns total to a larger multiple of 360, such as 2×360, which gives it a winding number of 2.
If we change the "magic formula" to
3 * 360 / n, we will get
a star with winding number 3. That
experiment is shown below.
star = (n, k) -> pen k for [1..n] fd 100 rt 3 * 360 / n speed 10 star 8, red
The problem is this: if the winding number evenly divides the number of corners, we retrace old corners exactly. For example, when using the winding number 2 with 8 points, 2 divides 8, and we retrace the same 4 corners twice. The winding number 3 works better.
An Algorithm With an Answer: Picking a Winding Number
How do we pick a winding number for
n-pointed star? We can write
an algorithm for that!
cfrom 2 to n as follows:
cnot a divisor of n:
cis our answer.
Translated from words into CoffeeScript:
winding = (n) -> # define a function named winding. for c in [2..n] # vary c from 2 to n, starting at 2. if (n % c) isnt 0 # if c is not a divisor of n then: return c # c is the answer. write winding 8 # run our function and write the answer.
Here are tools that we used to write this algorithm in CoffeeScript:
The "modulo" arithmetic operator, written
using the percent symbol
||Control. When inside a function,
windingfunction, and save it as "winding". Remember:
whilewill happen inside the loop.
returnthe answer outside the loop,
returnshould not be doubly-indented. But since the
returnis part of the function, it should be singly-indented.
windingfunction with different numbers, and note the outcomes below:
Using one Function inside Another
After we define
winding, we can
use it anywhere, including inside the
function. Here is how:
winding = (n) -> # define the function winding for c in [2..n] if (n % c) isnt 0 return c star = (n, k) -> # define the function star pen k w = winding n # use winding to pick w for [1..n] fd 100 rt w * 360 / n # use w as the winding number star 12, purple # draw a star!
The Importance of Testing
It is important to test algorithms! If you
test this algorithm carefully, you will find that
it still does not work for some values
n. For example,
star 18, red draws a shape
with only 9 stars.
It turns out that a better way to choose a winding number is to choose a number that has no common divisors with n (other than 1).
The following is Euclid's algorithm to calculate the greatest common divisor of two numbers:
gcd = (a, b) -> while b isnt 0 # repeat the indented lines while b isn't zero: if a > b # if a is greater than b, then do this: a = a - b # replace a with the difference (a - b) else # otherwise (if a is not greter than b): b = b - a # replace b with the difference (b - a) return a # after the loop is done, the answer is a
no common divisors, then
gcdto your program before you use it.
cthat satisfies the condition
gcd(n, c) is 1.
star 18, red? ______
n. Create a program "star4" that produces pointy stars:
floorrounds down, so
floor(n/2)is half of
n, rounded down.
stardraw the least-pointy shape? ______