// Pollen ex 12 by Mike Davis // mike [at] lightcycle [dot] org // A short program for alife experiments. // // Each cell is represented by a pixel on the display as well as an entry in // the Vector 'cells'. Cells each have a run() method, which performs actions // based on the cell's surroundings. Cells run one at a time (to avoid conflicts // like wanting to move to the same space) in random order. World w; Vector cells; int paramx1, paramx2, paramy1, paramy2; int spore1, spore2, bg; // set lower for smoother animation, higher for faster simulation int runs_per_loop = 10000; void setup() { size(200, 200); noBackground(); stroke(255); fill(255); bg = color(200, 128, 128); clearscr(); rect(0, height - 5, width, 5); w = new World(); cells = new Vector(); spore1 = color(0, 0, 0); spore2 = color(254, 254, 254); // Add a bunch of cells at random places for (int i = 0; i < 3000; i++) { int cX = (int)random(width); int cY = (int)random(height); if (w.get(cX, cY) == bg) { if (random(1) < 0.5) w.set(cX, cY, spore1); else w.set(cX, cY, spore2); cell a = new cell(cX, cY); cells.add(0, a); } } } void loop() { // Set parameters paramx1 = (int)(7 * (float)mouseX / width) - 2; paramx2 = (int)(7 * (float)(width - mouseX) / width) - 2; paramy1 = (int)(7 * (float)mouseY / height) - 2; paramy2 = (int)(7 * (float)(height - mouseY) / height) - 2; // Run cells in random order cell selected; for (int i = 0; i < runs_per_loop; i++) { selected = (cell)cells.elementAt(min((int)random(cells.size()), cells.size() - 1)); selected.run(); } } void clearscr() { for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) setPixel(x, y, bg); } class cell { int x, y; cell(int x, int y) { this.x = x; this.y = y; } // Perform action based on surroundings void run() { // Fix cell coordinates while(x < 0) x+=width; while(x > width - 1) x-=width; while(y < 0) y+=height; while(y > height - 1) y-=height; // Cell instructions int myColor = w.get(x, y); if (myColor == spore1) { if (w.get(x + 1, y) != bg && w.get(x + 1, y - 1) != bg) move(0, -1); else if (w.get(x - 1, y + 1) == bg && w.get(x, y + 1) == bg && w.get(x + 1, y + 1) == bg) move(0, 1); else if (w.get(x + 1, y) != bg && w.get(x + 1, y - 1) == bg) move(1, -1); else if (w.get(x - 1, y + 1) == bg && w.get(x, y + 1) == bg && w.get(x + 1, y + 1) == bg) move(0, 1); else if (w.get(x - 1, y) != bg && w.get(x - 1, y - 1) == bg) move(-1, -1); else move(paramx1, paramy1); } else if (myColor == spore2) { if (w.get(x - 1, y) != bg && w.get(x - 1, y - 1) != bg) move(0, -1); else if (w.get(x - 1, y + 1) == bg && w.get(x, y + 1) == bg && w.get(x + 1, y + 1) == bg) move(0, 1); else if (w.get(x - 1, y) != bg && w.get(x - 1, y - 1) == bg) move(-1, -1); else if (w.get(x - 1, y + 1) == bg && w.get(x, y + 1) == bg && w.get(x + 1, y + 1) == bg) move(0, 1); else if (w.get(x + 1, y) != bg && w.get(x + 1, y - 1) == bg) move(1, -1); else move(paramx2, paramy2); } } // Will move the cell (dx, dy) units if that space is empty void move(int dx, int dy) { if (w.get(x + dx, y + dy) == bg && !(dx == 0 && dy == 0)) { w.set(x + dx, y + dy, w.get(x, y)); w.set(x, y, bg); x += dx; y += dy; } } } // The World class simply provides two functions, get and set, which access the // display in the same way as getPixel and setPixel. The only difference is that // the World class's get and set do screen wraparound ("toroidal coordinates"). class World { void set(int x, int y, int c) { while(x < 0) x+=width; while(x > width - 1) x-=width; while(y < 0) y+=height; while(y > height - 1) y-=height; setPixel(x, y, c); } int get(int x, int y) { while(x < 0) x+=width; while(x > width - 1) x-=width; while(y < 0) y+=height; while(y > height - 1) y-=height; return getPixel(x, y); } } void mousePressed() { setup(); }