mirror of
https://github.com/nature-of-code/noc-book-2
synced 2024-11-17 07:49:05 +01:00
Notion - Update docs
This commit is contained in:
parent
1b3827759b
commit
97223425a2
3 changed files with 33 additions and 25 deletions
|
@ -66,8 +66,8 @@
|
|||
<p>Since the lines of code above are the first to appear in this book, I'd like to take a moment to highlight a few important conventions I'm using in code.</p>
|
||||
<ul>
|
||||
<li>Code will always appear in a <code>monospaced font</code>.</li>
|
||||
<li>Comments that address what is happening in the code float next to the code (appearance may vary depending on where you are reading this book).</li>
|
||||
<li>The highlighting matches the comments with their corresponding lines of code.</li>
|
||||
<li>Comments that address what is happening in the code float next to the code (appearance may vary depending on where you are reading this book!).</li>
|
||||
<li>The highlighting groups the comments with their corresponding lines of code.</li>
|
||||
<li>Code that appears broken up by paragraphs of text (like this one here) often appears as unfinished snippets. For example, the closing bracket — <code>}</code> — for the <code>Walker</code> class does not appear until later below.</li>
|
||||
</ul>
|
||||
</div><a data-type="indexterm" data-primary="class (Processing)" data-secondary="constructor"></a><a data-type="indexterm" data-primary="constructor"></a><a data-type="indexterm" data-primary="class (Processing)" data-secondary="functionality"></a><a data-type="indexterm" data-primary="functionality"></a>
|
||||
|
@ -77,12 +77,20 @@
|
|||
stroke(0);
|
||||
point(this.x, this.y);
|
||||
}</pre>
|
||||
<p>The second function directs the <code>Walker</code> object to take a step. Now, this is where things get a bit more interesting. Remember taking steps in random directions on a floor? Well, now a p5.js canvas can be used to represent that floor. There are four possible steps. A step to the right can be simulated by incrementing <code>x</code>—<code>x++</code>; to the left by decrementing <code>x</code>—<code>x--</code>; forward by going down a pixel—<code>y++</code>; and backward by going up a pixel—<code>y--</code>. How can the code pick from these four choices? Earlier I stated that you could flip two coins. In p5.js, however, when you want to randomly choose from a list of options, a random number of any range can be generated with the <code>random()</code> function.</p><a data-type="indexterm" data-primary="random number generators" data-secondary="random() function"></a><a data-type="indexterm" data-primary="random() function"></a>
|
||||
<p>The next function directs the <code>Walker</code> object to take a step. Now, this is where things get a bit more interesting. Remember taking steps in random directions on a floor? Well, now a p5.js canvas can be used to represent that floor. There are four possible steps. A step to the right can be simulated by incrementing <code>x</code>—<code>x++</code>; to the left by decrementing <code>x</code>—<code>x--</code>; forward by going down a pixel—<code>y++</code>; and backward by going up a pixel—<code>y--</code>. How can the code pick from these four choices? Earlier I stated that you could flip two coins. In p5.js, however, when you want to randomly choose from a list of options, a random number of any range can be generated with the <code>random()</code> function.</p>
|
||||
<pre class="codesplit" data-code-language="javascript">let choice = floor(random(4));</pre>
|
||||
<p>The above line of code declares a variable <code>choice</code> and assigns it a random integer (aka whole number) with a value of 0, 1, 2, or 3 (by removing the decimal places of a floating point random number using <code>floor()</code>.)</p>
|
||||
<div data-type="exercise">
|
||||
<h3 id="----declaring-variables----in-javascript-variables-can-be-declared-using-either-let-or-const-a-typical-approach-would-be-to-declare-all-variables-with-const-in-this-first-example-const-is-appropriate-for-choice-as-it-is-never-re-assigned-a-new-value-while-this-distinction-is-important-i-am-choosing-to-follow-the-p5js-example-convention-and-declare-all-variables-with-let-i-recognize-there-are-important-reasons-for-having-const-and-let-however-the-distinction-can-be-a-distraction-and-confusing-for-beginners-i-encourage-you-the-reader-to-explore-the-topic-further-and-make-your-own-decisions-about-how-to-best-declare-variables-in-your-own-sketches-for-more-you-can-read-this-discussion-on-the-p5js-github-repository--">
|
||||
Declaring Variables
|
||||
In JavaScript, variables can be declared using either let or const. A typical approach would be to declare all variables with const. In this first example const is appropriate for choice as it is never re-assigned a new value. While this distinction is important, I am choosing to follow the p5.js example convention and declare all variables with let. I recognize there are important reasons for having const and let. However, the distinction can be a distraction and confusing for beginners. I encourage you, the reader, to explore the topic further and make your own decisions about how to best declare variables in your own sketches. For more, you can read this discussion on the p5.js GitHub repository.
|
||||
</h3>
|
||||
</div>
|
||||
<p>Technically speaking, the random number picked can never be 4.0, but rather the highest possibility is 3.999999999 (with as many 9s as JavaScript will allow); since the <code>floor()</code> function lops off the decimal place, the highest possible whole number (aka <code>integer</code>) is 3. Next, the walker takes the appropriate step (left, right, up, or down) depending on which random number was picked. Here is the full <code>step()</code> function closing out the class <code>Walker</code>.</p>
|
||||
<pre class="codesplit" data-code-language="javascript"> step() {
|
||||
// 0, 1, 2, or 3
|
||||
let choice = floor(random(4));</pre>
|
||||
<p>The above line of code picks a random floating point number between 0 and 4 and converts it to an integer (aka whole number) with a result of 0, 1, 2, or 3. Technically speaking, the random number picked can never be 4.0, but rather the highest possibility is 3.999999999 (with as many 9s as there are decimal places); since the <code>floor()</code> function lops off the decimal place, the highest possible whole number (aka <code>integer</code>) is 3. Next, the walker takes the appropriate step (left, right, up, or down) depending on which random number was picked.</p>
|
||||
<pre class="codesplit" data-code-language="javascript"> //{!9} The random "choice" determines the step.
|
||||
let choice = floor(random(4));
|
||||
//{!9} The random "choice" determines the step.
|
||||
if (choice == 0) {
|
||||
this.x++;
|
||||
} else if (choice == 1) {
|
||||
|
@ -119,7 +127,7 @@
|
|||
</figure>
|
||||
</div>
|
||||
<p><em>Each time you see the above Example heading in this book, it means there is a corresponding code example available in the p5 web editor and found on the book’s website.</em></p>
|
||||
<p>There are a couple adjustments that could be made to the random walker. For one, this <code>Walker</code> object’s steps are limited to four options—up, down, left, and right. But any given pixel in the window has eight possible neighbors, and a ninth possibility is to stay in the same place.</p>
|
||||
<p>There are a couple adjustments that could be made to the random walker. For one, this <code>Walker</code> object’s steps are limited to four options—up, down, left, and right. But any given pixel in the canvas can be considered to have eight possible neighbors (including diagonals). A ninth possibility to stay in the same place could also be an option!</p>
|
||||
<figure>
|
||||
<img src="images/00_7_introduction/00_7_introduction_2.png" alt="Figure I.1">
|
||||
<figcaption>Figure I.1</figcaption>
|
||||
|
@ -186,7 +194,7 @@
|
|||
<p>Remember when you first started programming with p5.js? Perhaps you wanted to draw a lot of circles on the screen. So you said to yourself: “Oh, I know. I’ll draw all these circles at random positions, with random sizes and random colors.” When learning the basics of computer graphics, seeding a system with randomness is a perfectly reasonable starting point. In this book, however, I am looking to build systems modeled on what we see in nature. Defaulting to randomness is not a particularly thoughtful solution to a design problem—in particular, the kind of problem that involves creating an organic or natural-looking simulation.</p><a data-type="indexterm" data-primary="probability of the fittest"></a>
|
||||
<p>With a few tricks, the <code>random()</code> function can produce “non-uniform” distributions of random numbers. This will come in handy throughout the book for a variety of scenarios. In chapter 9's genetic algorithms, for example, I’ll need a methodology for performing “selection”—which members of the population should be selected to pass their DNA to the next generation? This is akin to the Darwinian concept of “survival of the fittest”. Say you have a population of monkeys evolving. Not every monkey has an equal chance of reproducing. To simulate Darwinian natural selection, you can’t simply pick two random monkeys to be parents. The more “fit” ones should be more likely to be chosen. This could be considered the “probability of the fittest.”</p><a data-type="indexterm" data-primary="probability"></a>
|
||||
<p>Let’s pause here and take a look at probability’s basic principles starting with single event probability, i.e. the likelihood that a given event will occur.</p>
|
||||
<p>If you have a system with a certain number of possible outcomes, the probability of the occurrence of a given event equals the number of outcomes that qualify as that event divided by the total number of all possible outcomes. A coin toss is a simple example—it has only two possible outcomes, heads or tails. There is only one way to flip heads. The probability that the coin will turn up heads, therefore, is one divided by two: 1/2 or 50%.</p>
|
||||
<p>If you have a system with a certain number of equally-likely possible outcomes, the probability of the occurrence of a given event equals the number of outcomes that qualify as that event divided by the total number of all possible outcomes. A coin toss is a simple example—it has only two possible outcomes, heads or tails. There is only one way to flip heads. The probability that the coin will turn up heads, therefore, is one divided by two: 1/2 or 50%.</p>
|
||||
<p>Take a deck of fifty-two cards. The probability of drawing an ace from that deck is:</p>
|
||||
<div data-type="equation">\textrm{number of aces } / \textrm{ number of cards} = 4 / 52 = 0.077 \approx 8\%</div>
|
||||
<p>The probability of drawing a diamond is:</p>
|
||||
|
@ -365,7 +373,7 @@
|
|||
xstep = random(-1, 1);
|
||||
ystep = random(-1, 1);
|
||||
}</pre><a data-type="indexterm" data-primary="Lévy flight" data-secondary="implementing with qualifying random values"></a>
|
||||
<p>However, this reduces the probabilities to a fixed number of options. What if you wanted to make a more general rule—the higher a number, the more likely it is to be picked? 6.145 would be more likely to be picked than 5.934, even if that likelihood is just a tiny bit greater. In other words, if <code>x</code> is the random number, the likelihood of it being picked could be mapped to the y-axis with the function <code>y = x</code>.</p>
|
||||
<p>However, this reduces the probabilities to a fixed number of options. What if you wanted to make a more general rule—the higher a number, the more likely it is to be picked? 0.8791 would be more likely to be picked than 0.8532, even if that likelihood is just a tiny bit greater. In other words, if <code>x</code> is the random number, the likelihood of it being picked could be mapped to the y-axis with the function <code>y = x</code>.</p>
|
||||
<figure class="half-width-right">
|
||||
<img src="images/00_7_introduction/00_7_introduction_3.png" alt="Figure I.3">
|
||||
<figcaption>Figure I.3</figcaption>
|
||||
|
|
|
@ -220,7 +220,7 @@ position = position + velocity;</pre><a data-type="indexterm" data-primary="addi
|
|||
}
|
||||
}</pre>
|
||||
<div data-type="note">
|
||||
<h3 id="basic-number-properties-with-vectors">Basic Number Properties with Vectors</h3>
|
||||
<h3 id="addition-properties-with-vectors">Addition Properties with Vectors</h3>
|
||||
<p>Addition with vectors follow the same algebraic rules as with real numbers.</p>
|
||||
<p><strong><em>The commutative rule:</em></strong> <span data-type="equation">\vec{u} + \vec{v} = \vec{v} + \vec{u}</span></p>
|
||||
<p><strong><em>The associative rule:</em></strong> <span data-type="equation">\vec{u} + (\vec{v} + \vec{w}) = (\vec{u} + \vec{v}) + \vec{w}</span></p>
|
||||
|
@ -474,7 +474,7 @@ function draw() {
|
|||
mouse.sub(center);
|
||||
|
||||
//{!3} The magnitude (i.e. length) of a vector can be accessed via the mag() function. Here it is used as the width of a rectangle drawn at the top of the window.
|
||||
const m = mouse.mag();
|
||||
let m = mouse.mag();
|
||||
fill(0);
|
||||
rect(0, 0, m, 10);
|
||||
|
||||
|
@ -799,7 +799,7 @@ let z = x + y;</pre>
|
|||
<pre class="codesplit" data-code-language="javascript">let v = createVector(0, 0);
|
||||
let u = createVector(4, 5);
|
||||
//{.line-through} Don’t be fooled; this is incorrect!!!
|
||||
const w = v.add(u);</pre>
|
||||
let w = v.add(u);</pre>
|
||||
<p>The above might seem like a good guess, but it’s just not the way the <code>p5.Vector</code> class works. If you look at the definition of <code>add()</code> . . .</p>
|
||||
<pre class="codesplit" data-code-language="javascript">add(v) {
|
||||
this.x = this.x + v.x;
|
||||
|
@ -823,7 +823,7 @@ v.add(u);</pre>
|
|||
<pre class="codesplit" data-code-language="javascript">let v = createVector(0, 0);
|
||||
let u = createVector(4, 5);
|
||||
//{.line-through .no-comment}
|
||||
const w = v.add(u);
|
||||
let w = v.add(u);
|
||||
//{.bold .no-comment}
|
||||
let w = p5.Vector.add(v, u);</pre>
|
||||
<p>The <code>p5.Vector</code> class has static versions of <code>add()</code>, <code>sub()</code>, <code>mult()</code>, and <code>div()</code>.</p>
|
||||
|
|
|
@ -176,7 +176,7 @@ m2.applyForce(wind);</pre>
|
|||
<h3 id="exercise-22">Exercise 2.2</h3>
|
||||
<p>There’s another way you could write the <code>applyForce()</code> function, using the static method <code>div()</code> instead of <code>copy()</code>. Rewrite <code>applyForce()</code> using the static method. For help with this exercise, review static methods in <a href="/vectors#19-static-vs-non-static-functions">Chapter 1</a>.</p>
|
||||
<pre class="codesplit" data-code-language="javascript">applyForce(force) {
|
||||
const f = _______._______(_______,_______);
|
||||
let f = _______._______(_______,_______);
|
||||
this.acceleration.add(f);
|
||||
}</pre>
|
||||
</div>
|
||||
|
@ -473,7 +473,7 @@ friction.mult(frictionMag);
|
|||
<img src="images/02_forces/02_forces_4.png" alt="Figure 2.4">
|
||||
<figcaption>Figure 2.4</figcaption>
|
||||
</figure><a data-type="indexterm" data-primary="drag force"></a><a data-type="indexterm" data-primary="fluid resistance" data-secondary="modeling"></a><a data-type="indexterm" data-primary="forces" data-secondary="fluid resistance"></a><a data-type="indexterm" data-primary="natural phenomena" data-secondary="fluid resistance" data-tertiary="modeling"></a><a data-type="indexterm" data-primary="viscous force"></a>
|
||||
<p>Friction also occurs when a body passes through a liquid or gas. This force has many different names, all really meaning the same thing: <em>viscous force</em>, <em>drag force</em>, <em>fluid resistance</em>. While the result is ultimately the same as our previous friction examples (the object slows down), the calculation of a drag force and how it behaves is different. Let’s look at the formula:</p>
|
||||
<p>Friction also occurs when a body passes through a liquid or gas. This force has many different names, all really meaning the same thing: <em>viscous force</em>, <em>drag force</em>, <em>air resistance</em>. While the result is ultimately the same as our previous friction examples (the object slows down), the calculation of a drag force and how it behaves is different. Let’s look at the formula:</p>
|
||||
<div data-type="equation">F_d = - \frac{1}{2}\rho\nu^2 A C_d\hat{\nu}</div>
|
||||
<p>Now let’s break this down and see what we really need for an effective simulation in p5, making a simpler formula in the process.</p>
|
||||
<ul>
|
||||
|
@ -481,9 +481,9 @@ friction.mult(frictionMag);
|
|||
<li>- 1/2 is a constant: -0.5. While it’s an important factor to scale the force, it’s not terribly relevant here, as I will be making up values for other scaling constants. However, the fact that it is negative is important, as it indicates that the force points in the opposite direction of velocity (just as with friction).</li>
|
||||
</ul><a data-type="indexterm" data-primary="rho (ρ)"></a><a data-type="indexterm" data-primary="friction" data-secondary="rho (ρ)"></a>
|
||||
<ul>
|
||||
<li><span data-type="equation">\rho</span> is the Greek letter <em>rho</em>, and refers to the density of the liquid, something you also don’t need to worry about at the moment. For my example I will consider this to have a constant value of 1.</li>
|
||||
<li><span data-type="equation">v</span> refers to the speed of the object moving. OK, you’ve got this one! The object’s speed is the magnitude of the velocity vector: <code>velocity.mag()</code>. And <span data-type="equation">v^2</span> just means <span data-type="equation">v</span> squared or <span data-type="equation">v \times v</span>.</li>
|
||||
<li><span data-type="equation">A</span> refers to the frontal surface area of the object that is pushing through the liquid (or gas). An aerodynamic Lamborghini, for example, will experience less air resistance than a boxy Volvo. Nevertheless, for a basic simulation, I will consider the object to be spherical and ignore this element.</li>
|
||||
<li><span data-type="equation">\rho</span> is the Greek letter <em>rho</em>, another constant that refers to the density of the liquid. I’ll choose to ignore this at the moment and consider it to have a constant value of 1.</li>
|
||||
<li><span data-type="equation">v</span> refers to the speed of the object moving. OK, you’ve got this one! The object’s speed is the magnitude of the velocity vector: <code>velocity.mag()</code>. And <span data-type="equation">v^2</span> just means <span data-type="equation">v</span> squared or <span data-type="equation">v \times v</span>. (I’ll note this assumes the liquid or gas is stationary and not moving, if you drop an object into a flowing river you’d have to also take the relative speed of the water into account!)</li>
|
||||
<li><span data-type="equation">A</span> refers to the frontal surface area of the object that is pushing through the liquid or gas. Consider a flat sheet of paper falling through the air and compare it to a sharp pencil pointed straight down. The pencil will experience less drag. Again, this is a constant and to keep things simple, I will consider all objects to have a spherical shape and ignore this element.</li>
|
||||
<li><span data-type="equation">C_d</span> is the coefficient of drag, exactly the same as the coefficient of friction (μ). This constant will determine the relative strength of the drag force.</li>
|
||||
<li><span data-type="equation">\hat{v}</span> Look familiar? It should. This refers to the velocity unit vector, i.e. <code>velocity.normalize()</code>. Just like with friction, drag is a force that points in the opposite direction of velocity.</li>
|
||||
</ul>
|
||||
|
@ -604,7 +604,7 @@ function draw() {
|
|||
<p>Running the example, you may notice that it appears to simulate objects falling into water. The objects only slow down when crossing through the gray area at the bottom of the window (representing the liquid). You’ll also notice that the smaller objects slow down a great deal more than the larger objects. Remember Newton’s second law? <code>A</code> = <code>F</code> / <code>M</code>. Acceleration equals force <em>divided</em> by mass. A massive object will accelerate less. A smaller object will accelerate more. In this case, the acceleration is the “slowing down” due to drag. The smaller objects slow down at a greater rate than the larger ones.</p>
|
||||
<div data-type="exercise">
|
||||
<h3 id="exercise-25">Exercise 2.5</h3>
|
||||
<p>Take a look at the formula for drag again: <strong><em>drag force = coefficient * speed * speed</em></strong>. The faster an object moves, the greater the drag force against it. In fact, an object not moving (velocity of zero) experiences no drag at all. Expand the example to drop the objects from variable height. How does this affect the drag as they hit the liquid?</p>
|
||||
<p>You might notice that if you set the coefficient of drag too high in the previous example, the circles may <em>bounce</em> off of the liquid! This is due to the inaccuracy of the large time steps that I mentioned earlier in this chapter. A drag force will cause an object to stop but never to reverse direction. How can you use the vector <code>limit()</code> function to correct this issue? You might also try dropping the objects from variables heights. How does this affect the drag as they hit the liquid?</p>
|
||||
</div>
|
||||
<div data-type="exercise">
|
||||
<h3 id="exercise-26">Exercise 2.6</h3>
|
||||
|
@ -660,7 +660,7 @@ dir.mult(magnitude);</pre>
|
|||
let force = p5.Vector.sub(position1, position2);
|
||||
|
||||
//{!1} The length (magnitude) of that vector is the distance between the two objects.
|
||||
const distance = force.mag();
|
||||
let distance = force.mag();
|
||||
|
||||
//{!1} Use the formula for gravity to compute the strength of the force.
|
||||
let magnitude = (G * mass1 * mass2) / (distance * distance);
|
||||
|
@ -812,7 +812,7 @@ function draw() {
|
|||
background(255);
|
||||
|
||||
//{!2} Apply the attraction force from the Attractor on the Mover.
|
||||
const force = a.attract(m);
|
||||
let force = a.attract(m);
|
||||
mover.applyForce(force);
|
||||
mover.update();
|
||||
|
||||
|
@ -844,9 +844,9 @@ class Attractor {
|
|||
}
|
||||
}</pre>
|
||||
<div data-type="exercise">
|
||||
<h3 id="exercise-2x-adapt-the-attractor-example-to-use-a-radius-property-for-the-attractor-and-mover-with-the-mass-scaled-by-the-area-of-the-circle-hint-since-the-area-of-a-circle-is-pi-r2-try-squaring-the-radius">Exercise 2.x Adapt the Attractor example to use a radius property for the Attractor and Mover with the mass scaled by the area of the circle (hint: since the area of a circle is \pi r^2 try squaring the radius!)</h3>
|
||||
<h3 id="exercise-2x-adapt-the-attractor-example-to-use-map-the-mass-of-the-attractor-and-mover-to-the-area-of-the-circle-hint-since-the-area-of-a-circle-is-pi-r2-try-taking-the-square-root-of-mass">Exercise 2.x Adapt the Attractor example to use map the mass of the Attractor and Mover to the area of the circle (hint: since the area of a circle is \pi r^2 try taking the square root of mass!)</h3>
|
||||
<pre class="codesplit" data-code-language="javascript">circle(this.position.x, this.position.y, ______(this.mass) * 2);</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<p>And you could, of course, expand this example to use an array for many <code>Mover</code> objects, just as I did with drag:</p>
|
||||
<div data-type="example">
|
||||
<h3 id="example-27-attraction-with-many-movers">Example 2.7: Attraction with many Movers</h3>
|
||||
|
@ -930,7 +930,7 @@ function draw() {
|
|||
//{!1} The Mover now knows how to attract another Mover.
|
||||
attract(other) {
|
||||
|
||||
const force = p5.Vector.sub(this.position, other.position);
|
||||
let force = p5.Vector.sub(this.position, other.position);
|
||||
let distance = force.mag();
|
||||
distance = constrain(distance, 5, 25);
|
||||
force.normalize();
|
||||
|
|
Loading…
Reference in a new issue