diff --git a/content/01_vectors.html b/content/01_vectors.html index 22a03098..2a8335cb 100644 --- a/content/01_vectors.html +++ b/content/01_vectors.html @@ -303,7 +303,7 @@

Exercise 1.1

Exercise 1.3

Extend the bouncing ball with vectors example into 3D. Can you get a sphere to bounce around a box?

-

1.4 More Vector Math

+

More Vector Math

Addition was really just the first step. There are many mathematical operations commonly used with vectors. Here’s a comprehensive table of the operations available as functions in the p5.Vector class.

diff --git a/content/02_forces.html b/content/02_forces.html index 9d4cde26..9f6c6943 100644 --- a/content/02_forces.html +++ b/content/02_forces.html @@ -907,7 +907,7 @@

Exercise 2.12

Exercise 2.13

This chapter isn’t suggesting that every good p5.js simulation needs to involve gravitational attraction. Rather, you should be thinking creatively about how to design your own rules to drive the behavior of objects, using my approach to simulating gravitational attraction as a model. For example, what happens if you design an attractive force that gets weaker as the objects get closer, and stronger as the objects get farther apart? Or what if you design your attractor to attract faraway objects, but repel close ones?

-

2.10 The n-Body Problem

+

The n-Body Problem

I started exploring gravitational attraction with a simple scenario, one object attracts another object, then moved on to the slightly more complex one object attracts many objects. A logical next step is to explore what happens when many objects attract many objects!

To begin, while it’s so far been helpful to have separate Mover and Attractor classes, this distinction is actually a bit misleading. After all, according to Newton's third law, all forces occur in pairs: if an attractor attracts a mover, then that mover should also attract the attractor. Instead of two different classes here, what I really want is a single type of thing—called, for example, a Body—with every body attracting every other body.

The scenario being described here is commonly referred to as the n-body problem. It involves solving for the motion of a group of objects that interact via gravitational forces. The two-body problem is a famously “solved” problem, meaning the motions can be precisely computed with mathematical equations when only two bodies are involved. However, adding one more body turns the two-body problem into a three-body problem, and suddenly no formal solution exists.

diff --git a/content/03_oscillation.html b/content/03_oscillation.html index 83012560..204b804d 100644 --- a/content/03_oscillation.html +++ b/content/03_oscillation.html @@ -1022,20 +1022,20 @@

Exercise 3.15

Before running to see the example online, take a look at this constrainLength method and see if you can fill in the blanks.

constrainLength(bob, minlen, maxlen) {
   //{!1} Vector pointing from Bob to Anchor
-  let direction = p5.Vector.sub(bob.position, this.anchor);
+  let direction = p5.Vector.sub(bob.position, this.anchor);
   let length = direction.mag();
 
   //{!1} Is it too short?
   if (length < minlen) {
-    direction.setMag(minlen);
+    direction.setMag(minlen);
     //{!1} Keep position within constraint.
-    bob.position = p5.Vector.add(this.anchor, direction);
+    bob.position = p5.Vector.add(this.anchor, direction);
     bob.velocity.mult(0);
   //{!1} Is it too long?
-  } else if (length > maxlen) {
-    direction.setMag(maxlen);
+  } else if (length > maxlen) {
+    direction.setMag(maxlen);
     //{!1} Keep position within constraint.
-    bob.position = p5.Vector.add(this.anchor, direction);
+    bob.position = p5.Vector.add(this.anchor, direction);
     bob.velocity.mult(0);
   }
 }
diff --git a/content/05_steering.html b/content/05_steering.html index 969d1fd7..57b103c1 100644 --- a/content/05_steering.html +++ b/content/05_steering.html @@ -443,10 +443,10 @@

Exercise 5.6

-
let x = i * width / cols;
-let y = j * height / rows;
-flowfield[i][j] = createVector(width/2 - x, height/2 - y);
-flowfield[i][j].rotate(PI / 2);
+
let x = i * width / cols;
+let y = j * height / rows;
+flowfield[i][j] = createVector(width/2 - x, height/2 - y);
+flowfield[i][j].rotate(PI / 2);

Now that I have a two-dimensional array storing the flow field vectors, I need a way for the vehicle to look up its desired velocity. For that, I simply divide the vehicle’s x and y position by the resolution of the grid. This gives me the indices of the desired vector in the 2D array. For example, if the resolution is 10 and the vehicle is at (100, 50), I’ll want to look up column 10 and row 5.

let column = floor(this.position.x / this.resolution);
diff --git a/content/06_libraries.html b/content/06_libraries.html
index 4062cda4..95622778 100644
--- a/content/06_libraries.html
+++ b/content/06_libraries.html
@@ -79,9 +79,9 @@ 

Matter.js Overview

The bad news: it’s not quite as simple as the pseudocode might lead you to believe. Actually making the stuff that goes into the Matter.js world involves several steps related to how different kinds of shapes are built and configured. It’s also necessary to learn to speak the language of Matter.js in terms of how the various forces and other parameters of the world are configured. Here are the core concepts:

  1. Engine. The entity that manages the physics simulation itself. The engine holds on to the “world” of the simulation as well as various properties about how the world is updated over time.
  2. -
  3. Body. Serves as the primary element in the world, corresponding to the physical objects being simulated. It has a position. It has a velocity. Sound familiar? It’s basically another version of the class I’ve been building all throughout Chapters 1 through 5. It also has geometry to define its shape. It’s important to note that “body” is a generic term that physics engines use to describe a “thing” in the world (similarly to the term “particle”); it isn’t related to an anthropomorphic body.
  4. +
  5. Bodies. Serve as the primary elements in the world, corresponding to the physical objects being simulated. A body has a position, and it has a velocity. Sound familiar? It’s basically another version of the class I’ve been building all throughout Chapters 1 through 5. It also has geometry to define its shape. It’s important to note that “body” is a generic term that physics engines use to describe a “thing” in the world (similarly to the term “particle”); it isn’t related to an anthropomorphic body.
  6. Composite. A container that allows for the creation of complex entities (made up of multiple bodies). The world itself is an example a composite, and every body created has be added to the world.
  7. -
  8. Constraint. Acts as a connection between two bodies.
  9. +
  10. Constraints. Act as connections between bodies.

In the coming sections, I’ll walk through each of these elements in detail, building several examples along the way. But first, there’s one other important element to briefly discuss.

    @@ -260,7 +260,7 @@

    Exercise 6.1

    friction: 0.5, restitution: 0.8, } -let ball = Bodies.circle(x, y, radius, options);
+let ball = Bodies.circle(x, y, radius, options);

Render

Once a body is added the world, Matter.js will always know it’s there, check it for collisions, and update its position appropriately according to any forces in the environment. It’ll do all that for you without you having to lift a finger! But how do you actually draw the body?

@@ -465,7 +465,7 @@

Exercise 6.2

Drag the mouse to add boxes.
-

Start with the code for 6.2 Boxes Exercise and, using the methodology outlined in this chapter, add the code to implement Matter.js physics. Delete bodies that have left the canvas. The result should appear as above. Feel free to be creative in how you draw the boxes!

+

Start with the code for Example 6.2 and, using the methodology outlined in this chapter, add the code to implement Matter.js physics. Delete bodies that have left the canvas. The result should appear as above. Feel free to be creative in how you draw the boxes!

Static Matter.js Bodies

In the example I just created, the Box objects appear at the mouse position and fall downwards due to the default gravity force. What if I want to add immovable boundaries to the world that will block the path of the falling Box objects? Matter.js makes this easy with the isStatic property.

@@ -568,7 +568,7 @@

Example 6.4: Polygon Shapes

// End the shape, closing it endShape(CLOSE); } -

The Matter.js body stores the array of its vertex positions inside a vertices property. Notice how I can then use a for…of loop to cycle through the vertices in between beginShape() and endShape().

+

The Matter.js body stores the array of its vertex positions inside a vertices property. Notice how I can then use a for...of loop to cycle through the vertices in between beginShape() and endShape().

Exercise 6.3

Using Bodies.fromVertices(), create your own polygon design (remember, it must be convex). Some possibilities are shown below.

@@ -604,7 +604,7 @@

Exercise 6.3

//{!2} Adding an offset from the x position of the lollipop's "stick" let offset = w / 2; let part2 = Bodies.circle(x + offset, y, r); -

Because there are two “parts” to the lollipop’s body, drawing it is a bit trickier. There are multiple approaches I could take. For example, I could use the body’s vertices array and draw the lollipop as a custom shape, much like in Example 6.4 (Every body stores an array of vertices, even if it wasn’t created with fromVertices()). Since each part of the lollipop is a primitive shape, however, I’d prefer to separately translate to each part’s position and rotate by the collective body’s angle.

+

Because there are two “parts” to the lollipop’s body, drawing it is a bit trickier. There are multiple approaches I could take. For example, I could use the body’s vertices array and draw the lollipop as a custom shape, much like in Example 6.4. (Every body stores an array of vertices, even if it wasn’t created with the fromVertices() method.) Since each part of the lollipop is a primitive shape, however, I’d prefer to separately translate to each part’s position and rotate by the collective body’s angle.

Example 6.5: Multiple Shapes on One Body

@@ -668,7 +668,7 @@

Distance Constraints

Figure 6.8: A constraint is a connection between two bodies at an anchor point for each body.
Figure 6.8: A constraint is a connection between two bodies at an anchor point for each body.
-

A distance constraint is a conection of fixed length between two bodies. The constraint is attached to each body at a specified anchor, a point relative to the body’s center (see Figure 6.8). However, it’s important to note that the “fixed” length can exhibit variability, depending on the constraint’s stiffness.

+

A distance constraint is a connection of fixed length between two bodies. The constraint is attached to each body at a specified anchor, a point relative to the body’s center (see Figure 6.8). Depending on the constraint’s stiffness, the “fixed” length of the constraint can exhibit variability.

Defining a constraint uses a similar methodology as creating bodies, only you need to have two bodies ready to go. Let’s assume there are two Particle objects that each store a reference to a Matter.js body in a property called body. I’ll call them particleA and particleB.

let particleA = new Particle();
 let particleB = new Particle();
@@ -695,7 +695,7 @@

Distance Constraints

let constraint = Constraint.create(options);
 //{!1} Don't forget to add the constraint to the world!
 Composite.add(engine.world, constraint);
-

Just like with a body, I can add a constraint to a class to encapsulate and manage the relationship between multiple bodies. Here’s an example of a class that represents a swinging pendulum (mirroring Example 3.x from Chapter 3).

+

I can include a constraint to a class to encapsulate and manage the relationship between multiple bodies. Here’s an example of a class that represents a swinging pendulum (mirroring Example 3.x from Chapter 3).

Example 6.6: Matter.js Pendulum

@@ -826,14 +826,14 @@

Example 6.7: Spinning Windmill

pop(); } } -

One thing you might wonder about in this example is the line representing the windmill stand. This stand is not a part of the Matter.js physics world, and I never created a body for it! This illustrates an important point about working with a physics engine alongside p5.js. You can add elements to the canvas that contribute to the visual design without affecting the physics, as long as you don't need them to participate in the simulation itself!

+

Notice the line in this example representing the windmill stand. It isn’t part of the Matter.js physics world, and I never created a body for it. This illustrates an important point about working with a physics engine alongside p5.js: you can add elements to the canvas that contribute to the visual design without affecting the physics, as long as you don’t need those elements to participate in the simulation itself.

Exercise 6.6

-

Create a vehicle that has revolute joints for its wheels. Consider the size and positioning of your wheels, how does changing the stiffness property affect its movement?

+

Create a vehicle that has revolute joints for its wheels. Consider the size and positioning of the wheels. How does changing the stiffness property affect their movement?

 
 
@@ -874,14 +874,14 @@

Example 6.8: MouseConstraint D

-

In the example, you'll see that the stiffness property of the constraint is set to 0.7, giving a bit of elasticity to the imaginary mouse string. Other properties such as angularStiffness and damping can also influence the mouse's interaction. Play around with these values. What happens if you adjust the stiffness?

+

In the example, you'll see that the stiffness property of the constraint is set to 0.7, giving a bit of elasticity to the imaginary mouse string. Other properties such as angularStiffness and damping can also influence the mouse's interaction. Play around with these values. What happens if you adjust the stiffness?

Bringing It All Back Home to Forces

In Chapter 2, I covered how to build an environment where there are multiple forces at play. An object might respond to gravitational attraction, wind, air resistance, and so on. Clearly, there are forces at work in Matter.js as rectangles and circles spin and fly around the screen! But so far, I’ve only actually demonstrated how to manipulate a single global force: gravity.

  let engine = Engine.create();
   // Changing the engine's gravity to point horizontally
   engine.gravity.x = 1;
   engine.gravity.y = 0;
-

If I want to use any of the Chapter 2 techniques with Matter.js, I need look no further than the trusty applyForce() method. In Chapter 2, I wrote this method as part of the Mover class. It received a vector, divided it by mass, and accumulated it into the mover’s acceleration. With Matter.js, the same method exists, so I no longer need to write all the details myself! I can call it with the static Body.applyForce(). Here is what that looks like, in what is now the equivalent Box class.

+

If I want to use any of the Chapter 2 techniques with Matter.js, I need look no further than the trusty applyForce() method. In Chapter 2, I wrote this method as part of the Mover class. It received a vector, divided it by mass, and accumulated it into the mover’s acceleration. With Matter.js, the same method exists, so I no longer need to write all the details myself! I can call it with the static Body.applyForce(). Here’s what that looks like in what’s now the Box class.

class Box {
 
   applyForce(force) {
@@ -944,7 +944,7 @@ 

Example 6.9 Attraction with Matter. let options = { frictionAir: 0 }; this.body = Bodies.circle(x, y, this.radius, options); }

-

This is a good time to revisit to the concept of mass. Although I'm accessing the mass property of the body associated with the mover, I never explicitly set it. In Matter.js, the mass of a body is automatically calculated based on its size (area) and density. Larger bodies will therefore have a greater mass. To increase the mass relative to the size, you can try setting a density property in the options object (the default is 0.001). For static bodies, such as the attractor, the mass is considered infinite. This is how the attractor stays stays locked in position despite the movers knocking into it continuously.

+

This is also a good time to revisit to the concept of mass. Although I'm accessing the mass property of the body associated with the mover in the attract() method, I never explicitly set it. In Matter.js, the mass of a body is automatically calculated based on its size (area) and density. Larger bodies will therefore have a greater mass. To increase the mass relative to the size, you can try setting a density property in the options object (the default is 0.001). For static bodies, such as the attractor, the mass is considered infinite. This is how the attractor stays locked in position despite the movers continuously knocking into it.

Exercise 6.7

Incorporate Body.applyForce() into a new spin() method for Example 6.7’s Windmill class to simulate a motor continuously rotating the windmill.

@@ -976,21 +976,21 @@

Collision Events

}

Notice that the function includes an event parameter. This is an object that includes all the data associated with a collision (or multiple collisions if more than one has occurred in that time step), such as which bodies are involved. Matter.js automatically creates this object and passes it along to the handleCollisions() callback every time there’s a collision.

Say I have a sketch with Particle objects that each store a reference to a Matter.js body, and I want the particles to change color when they collide with each other. Here’s the process to follow to make that happen.

-

Step 1: Event, could you tell me what two things collided?

+

Step 1: Event, could you tell me what two things collided?

Now, what has collided here? Matter.js detects collisions between a “pair” of bodies, these are the objects that have geometry. Any pair of colliding bodies will be in an array called pairs inside the event object. Inside handleCollisions(), I can use a for…of loop to iterate over those pairs.

for (let pair of event.pairs) {
 
 }
 
-

Step 2: Pair, could tell me which two bodies you include?

+

Step 2: Pair, could tell me which two bodies you include?

Each pair in the pairs array is an object with references to the two bodies involved in the collision, bodyA and bodyB. I’ll extract those bodies.

for (let pair of event.pairs) {
   let bodyA = pair.bodyA;
   let bodyB = pair.bodyB;
 }
-

Step 3: Bodies, could you tell me which Particles you’re associated with?

-

Getting from the relevant Matter.js bodies to the Particle objects they’re associated with is a little harder. After all, Matter.js doesn’t know anything about my code. Sure, it’s doing all sorts of stuff to keep track of the relationships between bodies and constraints, but it’s up to me to manage my own objects and their associations with Matter.js elements. That said, Matter.js provides a mechanism that allows a Body object to be attached to a custom object (in this case, a Particle). The link is made through the Body class’s plugin property. Every Matter.js body is instantiated with an empty object— { }— called plugin ready to go for to storing custom data.

-

Take a look at the updated constructor in the Particle class where the body is made. Note how the body-making procedure has been expanded by one line of code to set the plugin property. It’s important to add a new property (in this case plugin.particle) to the existing object rather than overwriting the pluginobject itself, which could potentially interfere with other features or customizations.

+

Step 3: Bodies, could you tell me which Particles you’re associated with?

+

Getting from the relevant Matter.js bodies to the Particle objects they’re associated with is a little harder. After all, Matter.js doesn’t know anything about my code. Sure, it’s doing all sorts of stuff to keep track of the relationships between bodies and constraints, but it’s up to me to manage my own objects and their associations with Matter.js elements. That said, every Matter.js body is instantiated with an empty object— { }— called plugin, ready to store any custom data about that body. I can link the body to a custom object (in this case, a Particle) by storing a reference to that object in the plugin property.

+

Take a look at the updated constructor in the Particle class where the body is made. Note how the body-making procedure has been expanded by one line of code to add a particle property inside plugin. It’s important to make sure you’re adding a new property to the existing plugin objet (in this case, plugin.particle = this) rather than overwriting the pluginobject itself (for example, with plugin = this). That latter could interfere with other features or customizations.

class Particle {
 
   constructor(x, y, radius) {
@@ -1180,7 +1180,7 @@ 

Vectors

-

Notice in particular how toxiclibs.js vectors are created by calling the Vec2D constructor with the new keyword, rather than by using a factory method like Matter.Vector()and createVector().

+

Notice in particular how toxiclibs.js vectors are created by calling the Vec2D constructor with the new keyword, rather than by using a factory method like Matter.Vector() or createVector().

The Physics World

The classes to describe the world and its particles and springs in toxiclibs.js are found in toxi.physics2d. I’m also going to use a Rect object (to describe a generic rectangle boundary) and GravityBehavior to apply a global gravity force to the world. Including Vec2D, I now have all the following class aliases.

@@ -1210,7 +1210,7 @@ 

The Physics World

}

Now all that remains is to populate the world.

Particles

-

The toxiclibs.js equivalent of a Matter.js body—a thing that exists in the world and experiences physics—is a particle, as represented by the VerletParticle2D class. However, unlike Matter.js bodies, toxiclibs particles do not store geometry.

+

The toxiclibs.js equivalent of a Matter.js body—a thing that exists in the world and experiences physics—is a particle, as represented by the VerletParticle2D class. However, unlike Matter.js bodies, toxiclibs particles don’t store geometry.

How should I integrate toxiclibs.js particles into a p5.js sketch? In the Matter.js examples, I created my own class (called, say, Particle) and included a reference to a Matter.js body.

class Particle {
   constructor(x, y, r) {
@@ -1272,7 +1272,7 @@ 

Springs

let spring = new VerletSpring2D(particle1, particle2, length, strength);

Just as with particles, in order for the connection to actually be part of the physics world, it must be explicitly added to the world.

physics.addSpring(spring);
-

I have almost everything I need to build a simple first toxiclibs example: two particles connected to form a springy pendulum. There’s one more element I want to ad, however: mouse interactivity.

+

I have almost everything I need to build a simple first toxiclibs example: two particles connected to form a springy pendulum. There’s one more element I want to add, however: mouse interactivity.

With Matter.js, I explained that the physics simulation breaks down if you manually override a body’s position by setting it to the mouse. With toxiclibs, this isn’t a problem. If I want to, I can set a particle’s (x, y) position manually. However, before doing so, it’s generally a good idea to call the particle’s lock() method, which fixes the particle in place. This is identical to setting the isStatic property to true in Matter.js.

The idea is to lock the particle temporarily so it stops responding to the world’s physics, alter its position, and then unlock it (with the unlock() method) so it can start moving again from its new location. For example, consider the scenario where I want to reposition a particle whenever the mouse is pressed.

  if (mouseIsPressed) {
@@ -1561,7 +1561,7 @@ 

Example 6.x Soft Body Character

particles[0].unlock(); } }
-

For the soft body character example, you’ll notice that I’m no longer drawing all the elements on the canvas! The show() function of the particles is not called, and the internal springs that give the character its structure are not rendered with lines. In fact, the springs themselves are never referenced after setup()since the character's shape is constructed from its particle positions. I do think, however, it's useful to keep the array as part of the example, considering it may be necessary for enhancing the sketch in the future.

+

For the soft body character example, you’ll notice that I’m no longer drawing all the elements of the physics simulation on the canvas! The show() method of the particles isn’t called, and the internal springs that give the character its structure are not rendered with lines. In fact, the springs themselves are never referenced after setup(), since the character’s shape is constructed from its particle positions. As such, the springs array isn’t strictly needed in this example, although I do fin it useful to have, considering it may be necessary for enhancing the sketch in the future.

Considering the drawing as its own problem, distinct from the character's skeletal structure, also opens up possibilities for adding other design elements such as eyes or antennae. These creative enhancements don't need to be directly connected to the physics of the character, although they can be if you choose to do so!

@@ -1678,7 +1678,7 @@

Example 6.13: Cluster

//{!1} Draw cluster cluster.show(); } -

This example illustrates the concept of a force-directed graph, but it does not involve any actual data! Here, the number of nodes in each cluster and the equilibrium length between the nodes are assigned randomly, and the spring strength has a constant value of 0.01. In a real-world application, these values could be determined based on your specific data, hopefully resulting in a meaningful visualization of the relationships within the data itself.

+

This example illustrates the concept of a force-directed graph, but it does not involve any actual data! Here, the number of nodes in each cluster and the equilibrium length between the nodes are assigned randomly, and the spring strength has a constant value of 0.01. In a real-world application, these values could be determined based on your specific data, hopefully resulting in a meaningful visualization of the relationships within the data itself.

Exercise 6.11

Design a cluster-like structure as a skeleton for a cute, cuddly, squishy creature. Add gravity and mouse interaction.

@@ -1722,7 +1722,7 @@

Attraction and Repulsion Behaviors -

I can now remake the attraction example from Chapter 2 with a single Attractor object that exerts an attraction behavior anywhere on the canvas. Even though the attractor is centered, I'm using a distance threshold of the full width to account for any movement of the attractor, or particles being outside the canvas boundaries.

+

I can now remake the attraction example from Chapter 2 with a single Attractor object that exerts an attraction behavior anywhere on the canvas. Even though the attractor is centered, I'm using a distance threshold of the full width to account for any movement of the attractor, and for particles located outside the canvas boundaries.

Example 6.14: Attraction (and Repulsion) Behaviors

@@ -1747,7 +1747,7 @@

Example 6.14: Attraction circle(this.x, this.y, this.r * 2); } } -

Just as discussed in Chapter 5’s section on spatial subdivision and “binning”, toxiclibs.js projects with large numbers of particles interacting with each other can run very slow due to N^2 nature of the algorithm (every particle checking every other particle). To speed up the simulation, you could potentially use the manual addForce()method in conjunction with an implemented binning algorithm. Keep in mind, this would also require you to manually calculate the attraction force, as the built-in AttractionBehavior would no longer apply.

+

Just as discussed in Chapter 5’s section on spatial subdivision and “binning”, toxiclibs.js projects with large numbers of particles interacting with each other can run very slow due to the N^2 nature of the algorithm (every particle checking every other particle). To speed up the simulation, you could potentially use the manual addForce()method in conjunction with a binning algorithm. Keep in mind, this would also require you to manually calculate the attraction force, as the built-in AttractionBehavior would no longer apply.

Exercise 6.13

Use AttractionBehavior in conjunction with spring forces.

diff --git a/content/09_ga.html b/content/09_ga.html index db16deb1..244f7fcb 100644 --- a/content/09_ga.html +++ b/content/09_ga.html @@ -562,8 +562,8 @@

Example 9.1: Genetic

-
// [TBD] Global variables needed for the GA
-
+
// [TBD] Global variables needed for the GA
+
 // Mutation rate
 let mutationRate = 0.01;
 // Population Size
@@ -577,15 +577,15 @@ 

Example 9.1: Genetic function setup() { createCanvas(640, 360); - //{!3} Step 1: Initialize Population - for (let i = 0; i < populationSize; i++) { + //{!3} Step 1: Initialize Population + for (let i = 0; i < populationSize; i++) { population[i] = new DNA(target.length); } } function draw() { - // Step 2: Selection + // Step 2: Selection //{!3} Step 2a: Calculate fitness. for (let i = 0; i < population.length; i++) { population[i].calculateFitness(target); @@ -602,7 +602,7 @@

Example 9.1: Genetic } } - // Step 3: Reproduction + // Step 3: Reproduction for (let i = 0; i < population.length; i++) { let aIndex = floor(random(matingPool.length)); let bIndex = floor(random(matingPool.length)); @@ -1294,7 +1294,7 @@

Exercise 9.12

-

9.12 Interactive Selection

+

Interactive Selection

In addition to Evolving Virtual Creatures, Sims is also well known for his museum installation Galapagos. Originally installed in the Intercommunication Center in Tokyo in 1997, the installation consists of twelve monitors displaying computer-generated images. These images evolve over time, following the genetic algorithm steps of selection and reproduction. The innovation here is not the use of the genetic algorithm itself, but rather the strategy behind the fitness function. In front of each monitor is a sensor on the floor that can detect the presence of a visitor viewing the screen. The fitness of an image is tied to the length of time that viewers look at the image. This is known as interactive selection, a genetic algorithm with fitness values assigned by people.

This strategy is far from being confined to art installations and is quite prevalent in the digital age of user-generated ratings and reviews. Could you imagine evolving the perfect song based on your Spotify ratings? Or the ideal book according to Goodreads reviews?