Skip to content

Commit

Permalink
Merge pull request #831 from nature-of-code/notion-update-docs
Browse files Browse the repository at this point in the history
[Notion] Update docs
  • Loading branch information
shiffman committed Feb 25, 2024
2 parents ae85bd6 + 624daeb commit 7603c18
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 20 deletions.
2 changes: 1 addition & 1 deletion content/07_ca.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ <h2 id="what-is-a-cellular-automaton">What Is a Cellular Automaton?</h2>
<li>Each cell has a <strong>neighborhood</strong>. This can be defined in any number of ways, but it’s typically all the cells adjacent to that cell.</li>
</ul>
<p>It’s important to stress that the cells in a CA don’t refer to biological cells (although you’ll see how CA can mimic lifelike behavior and have applications in biology). Instead, they simply represent discrete units in a grid, similar to the cells in a spreadsheet (as in Microsoft Ex<em>cel</em>). Figure 7.1 illustrates a CA and its various characteristics.</p>
<p>The second CA feature I listed—the idea that a cell’s state can vary over time—is an important new development. So far in this book, the objects (movers, particles, vehicles, boids, bodies) have generally existed in only one state. They might have moved with sophisticated behaviors and physics, but ultimately they remained the same type of object over the course of their digital lifetime. I’ve alluded to the possibility that these entities can change over time (for example, the weights of steering “desires” can vary), but I haven’t fully put this into practice. Now, with CA, you’ll see how an object’s state can change based on a system of rules.</p>
<figure>
<img src="images/07_ca/07_ca_2.png" alt="Figure 7.1: A 2D grid of cells, each with a state of on or off. A neighborhood is a subsection of the large grid, usually consisting of all the cells adjacent to a given cell (circled).">
<figcaption>Figure 7.1: A 2D grid of cells, each with a state of <em>on</em> or <em>off</em>. A neighborhood is a subsection of the large grid, usually consisting of all the cells adjacent to a given cell (circled).</figcaption>
</figure>
<p>The second CA feature I listed—the idea that a cell’s state can vary over time—is an important new development. So far in this book, the objects (movers, particles, vehicles, boids, bodies) have generally existed in only one state. They might have moved with sophisticated behaviors and physics, but ultimately they remained the same type of object over the course of their digital lifetime. I’ve alluded to the possibility that these entities can change over time (for example, the weights of steering “desires” can vary), but I haven’t fully put this into practice. Now, with CA, you’ll see how an object’s state can change based on a system of rules.</p>
<p>The development of CA systems is typically attributed to Stanisław Ulam and John von Neumann, who were both researchers at the Los Alamos National Laboratory in New Mexico in the 1940s. Ulam was studying the growth of crystals, and von Neumann was imagining a world of self-replicating robots. You read that right: robots that can build copies of themselves.</p>
<p>Von Neumann’s original cells had 29 possible states, so perhaps the idea of self-replicating robots is a bit too complex of a starting point. Instead, imagine a row of dominoes; each domino can be in one of two states: standing upright (1) or knocked down (0). Just as dominoes react to their neighboring dominoes, the behavior of each cell in a CA is influenced by the states of its neighboring cells.</p>
<p>This chapter explores how even the most basic rules of something like dominoes can lead to a wide array of intricate patterns and behaviors, similar to natural processes like biological reproduction and evolution. Von Neumann’s work in self-replication and CA is conceptually similar to what’s probably the most famous CA, the Game of Life, which I’ll discuss in detail later in the chapter.</p>
Expand Down
25 changes: 6 additions & 19 deletions content/08_fractals.html
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@ <h3 id="drawing-the-cantor-set-with-recursion">Drawing the Cantor Set with Recur
<p>The Cantor rule operates by duplicating the original line and erasing its middle third section, leaving two remaining lines—one from the beginning to the one-third mark, and one from the two-thirds mark to the end of the line (see Figure 8.9). I can implement that rule manually by calling <code>line()</code> two more times, moving the y-position down 20 pixels so that the next generation of lines appears below the first.</p>
<pre class="codesplit" data-code-language="javascript">function cantor(x, y, length) {
line(x, y, x + length, y);

//{.bold} From start to one-third
line(x, y + 20, x + length / 3, y + 20);
//{!1 .bold} From two-thirds to the end
Expand Down Expand Up @@ -305,7 +304,6 @@ <h3 id="the-monster-curve">The Monster Curve</h3>
let start = createVector(0, 200);
// Right side of the canvas
let end = createVector(width, 200);

//{!1} The first <code>KochLine</code> object
segments.push(new KochLine(start, end));
}</pre>
Expand All @@ -328,7 +326,6 @@ <h3 id="the-monster-curve">The Monster Curve</h3>
let next = [];
// For every segment . . .
for (let segment of segments) {

//{!4} . . . add four new lines. How do you calculate the start and end points of each?
next.push(new KochLine(???, ???));
next.push(new KochLine(???, ???));
Expand Down Expand Up @@ -387,10 +384,8 @@ <h3 id="the-monster-curve">The Monster Curve</h3>
let v = p5.Vector.sub(this.end, this.start);
// Shorten the length to one-third.
v.div(3);

//{!1} Add that vector to the beginning of the line to find the new point.
let b = p5.Vector.add(a, v);

// <code>d</code> is just another one-third of the way past <code>b</code>!
let d = p5.Vector.add(b, v);</pre>
</div>
Expand All @@ -402,7 +397,7 @@ <h3 id="the-monster-curve">The Monster Curve</h3>
</div>
<p>The last point, <em>c</em>, is the most difficult one to compute. However, if you consider that the angles of an equilateral triangle are all 60 degrees, this makes your work suddenly easier. If you know how to find the new <em>b</em> with a vector one-third the length of the line, what if you rotate that same vector 60 degrees (or <span data-type="equation">\pi/3</span> radians) and add it to <em>b</em>, as in Figure 8.16? You’d arrive at <em>c</em>!</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript"> //{!1} Rotate by –PI/3 radians (negative angle so it rotates “up”).
<pre class="codesplit" data-code-language="javascript"> //{!1} Rotate by –π/3 radians (negative angle so it rotates “up”).
v.rotate(-PI / 3);
//{!1} Move along from <code>b</code> by <code>v</code> to get to point <code>c</code>.
let c = p5.Vector.add(b, v);</pre>
Expand Down Expand Up @@ -481,7 +476,7 @@ <h3 id="the-deterministic-version">The Deterministic Version</h3>
</figure>
<p>Here’s the code for the process illustrated in Figure 8.18. I’m using an angle of 30 degrees, or <span data-type="equation">\pi/6</span> radians:</p>
<pre class="codesplit" data-code-language="javascript">translate(0, -100);
//{$1} PI divided by 6 is equivalent to 30°.
//{$1} π divided by 6 is equivalent to 30°.
rotate(PI / 6);
line(0, 0, 0, -100);</pre>
<p>Now that I have a branch going to the right, I need one going to the left (see Figure 8.19). For that, I should have used <code>push()</code> to save the transformation state before rotating and drawing the right branch. Then I’ll be able to call <code>pop()</code> after drawing the right branch to restore that state, putting me back in the correct position to rotate and draw the left branch.</p>
Expand Down Expand Up @@ -602,7 +597,7 @@ <h3 id="exercise-88">Exercise 8.8</h3>
<h3 id="the-stochastic-version">The Stochastic Version</h3>
<p>At first glance (and with the right angle), it may look like I’ve drawn a convincing tree in the previous example, but on closer inspection, the result is a little too perfect. Take a look outside at a real tree and you’ll notice that the branch lengths and angles vary from branch to branch, not to mention the fact that not all branches split off into exactly two smaller branches. Fractal trees are a great example of how adding a touch of randomness can make the end result look more natural. That bit of randomness also transforms the fractal from deterministic to stochastic—the exact outcome will be different from drawing to drawing, while still retaining the overall characteristics of a branching, tree-like structure.</p>
<p>First, how about randomizing the angle for each branch? This is a pretty easy one to do just by adding <code>random()</code>:</p>
<pre class="codesplit" data-code-language="javascript"> //{!1} Pick a random angle from 0 to PI/3 for each branch.
<pre class="codesplit" data-code-language="javascript"> //{!1} Pick a random angle from 0 to π/3 for each branch.
let angle = random(0, PI / 3);</pre>
<p>In the original example, <code>branch()</code> always calls itself twice. Now, for extra variety, I’ll instead pick a random number of branches (each with a random angle) for each branch.</p>
<div data-type="example">
Expand Down Expand Up @@ -645,10 +640,8 @@ <h2 id="l-systems">L-systems</h2>
<p>Implementing an L-system in p5.js requires working with recursion, transformations, and strings of text. This chapter already covers recursion and transformations, but strings are new. Here’s a quick snippet of code demonstrating the three aspects of working with text important to L-systems: creating, concatenating, and iterating over strings. You can refer to the book’s website for additional string resources and tutorials.</p>
<pre class="codesplit" data-code-language="javascript">// A string is created as text between quotes (single or double).
let message1 = "Hello!";

// Strings can be joined (concatenated) with the plus operator. The string is now "Hello Goodbye!"
let message2 = message1 + " Goodbye!";

// The length of a string is stored in its length property.
for (let i = 0; i &#x3C; message.length; i++) {
//{!1} Individual characters can be accessed by an index, just like an array! I’m using <code>charAt(i)</code> instead of <code>[i]</code>.
Expand Down Expand Up @@ -692,10 +685,10 @@ <h2 id="l-systems">L-systems</h2>
<p>Now it’s time to apply the production rules to <code>current</code> and write the results to <code>next</code>:</p>
<pre class="codesplit" data-code-language="javascript">for (let i = 0; i &#x3C; current.length; i++) {
let c = current.charAt(i);
//{!1} Production rule AAB
//{!1} Production rule AAB
if (c === "A") {
next += "AB";
//{!1} Production rule BA
//{!1} Production rule BA
} else if (c === "B") {
next += "A";
}
Expand All @@ -717,7 +710,6 @@ <h3 id="example-88-simple-l-system-sentence-generation">Example 8.8: Simple L-sy
createCanvas(640, 160);
background(255);
noLoop();

// Go through nine generations.
for (let i = 0; i &#x3C; 9; i++) {
generate();
Expand All @@ -733,7 +725,7 @@ <h3 id="example-88-simple-l-system-sentence-generation">Example 8.8: Simple L-sy
for (let i = 0; i &#x3C; current.length; i++) {
// For every character of the current sentence . . .
let c = current.charAt(i);
//{!5} . . . apply the production rules AAB, BA.
//{!5} . . . apply the production rules AAB, BA.
if (c === "A") {
next += "AB";
} else if (c === "B") {
Expand Down Expand Up @@ -875,10 +867,8 @@ <h3 id="example-88-simple-l-system-sentence-generation">Example 8.8: Simple L-sy
</table>
<p>Assuming I’ve generated a sentence from the L-system, I can iterate through the sentence character by character and execute the appropriate code for each character:</p>
<pre class="codesplit" data-code-language="javascript">for (let i = 0; i &#x3C; sentence.length; i++) {

//{!1} Look at each character one at a time.
let c = sentence.charAt(i);

//{!14} Perform the correct task for each character.
// This could also be written with a switch statement,
// which might be nicer to look at, but leaving it as an
Expand Down Expand Up @@ -939,15 +929,12 @@ <h3 id="example-89-an-l-system">Example 8.9: An L-system</h3>
let rules = {
"F": "FF+[+F-F-F]-[-F+F+F]",
};

// The L-system is created with an axiom and a ruleset.
lsystem = new LSystem("F", rules);

// Run the L-system through four generations.
for (let i = 0; i &#x3C; 4; i++) {
lsystem.generate();
}

//{!2 .offset} The <code>Turtle</code> object has a length and angle.
turtle = new Turtle(4, radians(25));
}
Expand Down

0 comments on commit 7603c18

Please sign in to comment.