Merge pull request #831 from nature-of-code/notion-update-docs

[Notion] Update docs
This commit is contained in:
Daniel Shiffman 2024-02-24 20:36:57 -05:00 committed by GitHub
commit 7603c18b63
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 7 additions and 20 deletions

View file

@ -27,11 +27,11 @@
<li>Each cell has a <strong>neighborhood</strong>. This can be defined in any number of ways, but its typically all the cells adjacent to that cell.</li>
</ul>
<p>Its important to stress that the cells in a CA dont refer to biological cells (although youll 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 cells 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. Ive alluded to the possibility that these entities can change over time (for example, the weights of steering “desires” can vary), but I havent fully put this into practice. Now, with CA, youll see how an objects 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 cells 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. Ive alluded to the possibility that these entities can change over time (for example, the weights of steering “desires” can vary), but I havent fully put this into practice. Now, with CA, youll see how an objects 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 Neumanns 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 Neumanns work in self-replication and CA is conceptually similar to whats probably the most famous CA, the Game of Life, which Ill discuss in detail later in the chapter.</p>

View file

@ -211,7 +211,6 @@ function drawCircles(x, y, radius) {
<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
@ -305,7 +304,6 @@ function drawCircles(x, y, radius) {
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>
@ -328,7 +326,6 @@ function drawCircles(x, y, radius) {
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(???, ???));
@ -387,10 +384,8 @@ function drawCircles(x, y, radius) {
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>
@ -402,7 +397,7 @@ function drawCircles(x, y, radius) {
</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? Youd 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>
@ -481,7 +476,7 @@ function setup() {
</figure>
<p>Heres the code for the process illustrated in Figure 8.18. Im 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 Ill 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>
@ -602,7 +597,7 @@ function draw() {
<h3 id="the-stochastic-version">The Stochastic Version</h3>
<p>At first glance (and with the right angle), it may look like Ive 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 youll 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, Ill instead pick a random number of branches (each with a random angle) for each branch.</p>
<div data-type="example">
@ -645,10 +640,8 @@ function draw() {
<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. Heres 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 books 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! Im using <code>charAt(i)</code> instead of <code>[i]</code>.
@ -717,7 +710,6 @@ function setup() {
createCanvas(640, 160);
background(255);
noLoop();
// Go through nine generations.
for (let i = 0; i &#x3C; 9; i++) {
generate();
@ -875,10 +867,8 @@ translate(0, length);</code></pre>
</table>
<p>Assuming Ive 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
@ -939,15 +929,12 @@ function setup() {
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));
}