![]() |
Jupyter at Bryn Mawr College |
|
|
Public notebooks: /services/public/dblank / CS110 Intro to Computing / 2015-Spring / Notes |
Consider a simple termite that only follows these simple rules:
Now, imagine a few of these termites roaming around a flat world, scattered with wood chips. What would happen? How can we model this world?
First, we must identify the objects we wish to model. Possibilities include:
First, let's consider what properties a termite should have:
Also, what actions must a termite be able to do:
We might want to add other methods, but it needs to at least support those.
So, let's put together a termite class. It might look something like:
class Termite {
int x;
int y;
int vx;
int vy;
int carrying;
Termite(int x, int y) { //constructor
this.x = int(x);
this.y = int(y);
this.randomizeDirection();
this.carrying = 0;
}
...
}
In thinking about the world, and wood chips, it might be that representing them as an object might be overkill. For example, if we imagine the world as a 2D matrix, then we could represent the presence of food with a 1, and the absence of food with a 0. Likewise, carrying can just be a 1 (for yes), and 0 (for no).
It may be that instead of having termites bounce off of the walls (like a ball simulation) that we instead have them "wrap" around (like a torus). For example, if a termite goes too far to the left, it will wrap around to the right, and instantly appear there. Likewise, if a turtle goes below 0 or above height, then it wraps back around. Thus, we implement an infinite, repeating surface.
This putting it all together might look like the following.
Note:
Termite [] termites; // the array of termites; we'll decide how many later
int[][] gworld; // the 2D world
int RADIUS = 5; // distance that we can sense a wood chip
class Termite {
int x;
int y;
int vx;
int vy;
int carrying; // zero - not carying chip; 1 - carrying chip
Termite(int x, int y) {
this.x = int(x);
this.y = int(y);
this.randomizeDirection();
this.carrying = 0;
}
void draw() {
if (this.carrying == 0) {
fill(0);
} else {
fill(255, 0, 0);
}
ellipse(this.x, this.y, 10, 5);
}
int get_x(int delta) {
int dx = this.x + delta;
if (dx >= width)
dx -= width;
if (dx < 0)
dx += width;
return dx;
}
int get_y(int delta) {
int dy = this.y + delta;
if (dy >= height)
dy -= height;
if (dy < 0)
dy += height;
return dy;
}
void step() {
this.x = this.get_x(this.vx);
this.y = this.get_y(this.vy);
}
void randomizeDirection() {
this.vx = 0;
this.vy = 0;
while (this.vx == 0 && this.vy == 0) {
this.vx = floor(random(3)) - 1;
this.vy = floor(random(3)) - 1;
}
}
void pickup_chip(int nx, int ny) {
// Pick it up!
world[nx][ny] = 0;
this.carrying = 1;
}
void drop_chip(int nx, int ny) {
// Drop it!
world[nx][ny] = 1;
this.carrying = 0;
}
void move() {
if (random() < .01) { // 1% of the time, change directions
this.randomizeDirection();
}
this.step();
// not carrying a woodchip
if (this.carrying == 0) { // can you smell a chip?
for (int i = -RADIUS; i <= RADIUS; i++) {
if (this.carrying == 0) {
for (int j = -RADIUS; j <= RADIUS; j++) {
nx = this.get_x(i);
ny = this.get_y(j);
if (world[nx][ny] == 1) { // yes!
this.pickup_chip(nx, ny);
break;
}
}
}
}
} else { // carrying a woodchip
// is there a chip nearby?
boolean found = false;
for (int i = -1; i <= 1; i++) {
if (!found) {
for (int j = -1; j <= 1; j++) {
nx = this.get_x(i);
ny = this.get_y(j);
if (world[nx][ny] == 1) { // yes!
// One nearby!
found = true;
break;
}
}
}
}
if (found) {
// now, find an empty spot nearby and drop it!
for (int i = -1; i <= 1; i++) {
if (this.carrying == 1) {
for (int j = -1; j <= 1; j++) {
nx = this.get_x(i);
ny = this.get_y(j);
if (world[nx][ny] == 0) {
// Drop it!
this.drop_chip(nx, ny);
break;
}
}
}
}
}
if (this.carrying == 0) {
// head in opposite direction
this.vx = -this.vx;
this.vy = -this.vy;
// make sure you are far enough away
for (int i = 0; i < RADIUS * 1.5; i++) {
this.step();
}
}
}
}
}
void setup() {
size(250, 250); // the world
termites = new Termite[10]; // start termites
for (int i =0; i < termites.length; i++) {
termites[i] = new Termite(random(width), random(height));
}
world = new int[width][height]; // match the canvas size
for (int i =0; i < width; i++) {
for (int j =0; j < height; j++) {
world[i][j] = 0;
}
}
for (int i =0; i < 200; i++) { // put some wood chips out:
world[int(random(width))][int(random(height))] = 1;
}
}
void draw() {
background();
noStroke();
// Move the termites:
for (int i =0; i < termites.length; i++) {
termites[i].move();
termites[i].draw();
}
// Draw them:
for (int i =0; i < width; i++) {
for (int j =0; j < height; j++) {
if (world[i][j] == 1) {
fill(255, 0, 0);
rect(i, j, 3, 3);
}
}
}
}