Look at a fern leaf, a horse's mane braid, or a real tree. A branch splits into smaller branches, and each of those splits into even smaller ones. Every small branch looks like a tiny copy of the whole tree. In geometry, shapes that are the same but at a different size are called similar. Code can draw them with a trick called recursion: a function that calls itself to do a smaller version of its own job. Last session binary search kept shrinking its problem (100, 50, 25 ...). Recursion is the same habit written as a function.
n - 1).This function prints a countdown. Read it slowly: it contains a call to countdown inside countdown.
Here is exactly what the computer does. Each call waits for the call below it to finish. This pile of waiting calls is called the call stack.
countdown(3) n is 3, not 0. Print 3. Call countdown(2).countdown(2) Print 2. Call countdown(1).countdown(1) Print 1. Call countdown(0).countdown(0) Base case! Print Go! and return. No more calls.Then each call finishes in turn (1, then 2, then 3). Nothing is left to do after the recursive call, so the output is:
That is 4 calls in total: one for each of 3, 2, 1, and one for 0.
Imagine we forgot the base case:
On paper: countdown(3) prints 3 and calls countdown(2). That prints 2 and calls countdown(1), then 0, then -1, then -2, and nothing ever says stop. Every call is still waiting, so the stack grows taller and taller. After roughly ten thousand calls the browser gives up and shows a red error: RangeError: Maximum call stack size exceeded. So the base case is not decoration. It is the part that makes the function finish. (We will never run this version. The tree below has a safety limit of 8 levels.)
A tree is perfect for recursion. Drawing a tree of depth d means: draw one branch, then at its tip draw two smaller trees of depth d - 1, one leaning left and one leaning right. The base case is depth 0: draw nothing.
Each new level has twice as many branches as the one before: 1, 2, 4, 8 ... (the powers of 2 from c17). Adding them up, a tree of depth n has 2n minus 1 branches: 1, 3, 7, 15, 31, 63, 127, 255. Depth 8 has 255 branches.
The geometry link: every branch is a copy of its parent shrunk by the same scale factor, 0.7. A trunk of 62 pixels has children of about 43 pixels, then about 30 pixels. The angles never change, only the size, so every sub-tree is similar to the whole tree.
Tap the picture to add one level of depth (after 8 it goes back to 1). Use the buttons to go deeper or shallower, and drag the slider to change the angle between branches. Watch the branch count double.
branch calls itself twice, so the number of calls doubles at every level. That is why a depth-8 tree has 255 branches but needs very little code.d - 1, so d counts down toward 0, just like the countdown. At d === 0 the base case returns and that part of the tree stops growing.translate moves the starting point to the branch tip. push() and pop() save and restore the position, so after drawing the right branch, the left one starts again from the same tip.How many calls does countdown(5) make in total, including the base case? What does the base case of branch do?
Answer: 6 calls (for 5, 4, 3, 2, 1 and 0). The base case of branch is d === 0: it returns at once, so nothing is drawn and no more calls start.
Copy the tree code into your p5 editor to try these. Keep the depth at 8 or below.
0.7 to 0.5, then to 0.85. Describe each tree in one sentence. Which factor makes the tree look like a bushy bush, and why do the branches overlap?countup(3) prints before you run it. Then run it in your editor and compare. What changed compared to countdown, and why?
d === 1, draw a pink circle (about 8 pixels wide) at the tip of the branch. Remember that after translate(0, -len) the tip is at (0, 0).rotate(0), scaled by 0.7, with d - 1). Predict how many branches a depth-3 tree now has, then check by counting. Keep the depth at 6 or lower, because this tree grows much faster.countup(3) prints 1 2 3. The print happens after the recursive call, so the deepest call finishes first: countup(0) returns, then 1 prints, then 2, then 3.rotate(angle). The second one must be rotate(-angle), a minus sign, so it leans the other way.if (d === 1) { fill('#ec4899'); circle(0, 0, 8); } after the translate line.