Fun with Fractals
In these exercises we're trying to sharpen your eye for recursive structure.
The Chessboard
Our first image is the chessboard. Though arguably not a fractal, the chessboard does contain itself: a 4x4 chessboard can be constructed from 4 2x2 chessboards, an 8x8 from 4 4x4s, and so on. The picture below shows this.
Your mission in this exercise is to identify the recursive structure in a chessboard, and implement a method to draw chessboards. The method skeleton is
def chessboard(count: Int): Image =
???
Implement chessboard
. Remember we can use the structural recursion skeleton and reasoning technique to guide our implementation.
chessboard
is a structural recursion over the natural numbers, so right away we can write down the skeleton for this pattern.
def chessboard(count: Int): Image =
count match {
case 0 => resultBase
case n => resultUnit add chessboard(n-1)
}
As before we must decide on the base, unit, and addition for the result. We've given you a hint by showing the progression of chessboards in Figure recursion:chessboards. From this we can see that the base is a two-by-two chessboard.
val blackSquare = Image.rectangle(30, 30).fillColor(Color.black)
val redSquare = Image.rectangle(30, 30).fillColor(Color.red)
val base =
(redSquare.beside(blackSquare)).above(blackSquare.beside(redSquare))
Now to work out the unit and addition.
Here we see a change from previous examples.
The unit is the value we get from the recursive call chessboard(n-1)
.
The addition operation is (unit.beside(unit)).above(unit.beside(unit))
.
Putting it all together we get
def chessboard(count: Int): Image = {
val blackSquare = Image.rectangle(30, 30).fillColor(Color.black)
val redSquare = Image.rectangle(30, 30).fillColor(Color.red)
val base =
(redSquare.beside(blackSquare)).above(blackSquare.beside(redSquare))
count match {
case 0 => base
case n =>
val unit = chessboard(n-1)
(unit.beside(unit)).above(unit.beside(unit))
}
}
If you have prior programming experience you might have immediately thought of creating a chessboard via two nested loops. Here we're taking a different approach by defining a larger chessboard as a composition of smaller chessboards. Grasping this different approach to decomposing problems is a key step in becoming proficient in functional programming.
Sierpinkski Triangle
The Sierpinski triangle, show below is a famous fractal. (Technically, Figure fractals:sierpinski shows a Sierpinkski triangle.)
Although it looks complicated we can break the structure down into a form that we can generate with structural recursion over the natural numbers. Implement a method with skeleton
def sierpinski(count: Int): Image =
???
No hints this time. We've already seen everything we need to know.
The key step is to recognise that the basic unit of the Sierpinski triangle is triangle.above(triangle.beside(triangle))
.
Once we've worked this out, the code has exactly the same structure as chessboard
.
Here's our implementation.
def sierpinski(count: Int): Image = {
val triangle = Image.triangle(10, 10).strokeColor(Color.magenta)
count match {
case 0 => triangle.above(triangle.beside(triangle))
case n =>
val unit = sierpinski(n-1)
unit.above(unit.beside(unit))
}
}