Hi everyone! I was trying to implement the Game of Life using Processing but my code is not working as it’s supposed to be. I’ve already looked up on the internet and it seems to me that my implementation looks very close to all the ones that i’ve looked at, so I’m not able to understand the problem… here’s my code:
Cell[][] grid;
int cellSize = 10;
void setup() {
size(800, 800);
grid = new Cell[width/cellSize][height/cellSize];
myInit();
}
void draw() {
showGrid();
createNewGeneration();
}
void myInit() {
int w = width/cellSize;
int h = height/cellSize;
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
grid[i][j] = new Cell(cellSize*i + cellSize/2, cellSize*j + cellSize/2, false);
}
}
grid[40][40].alive = true;
grid[41][41].alive = true;
grid[41][42].alive = true;
grid[40][42].alive = true;
grid[39][42].alive = true;
}
void showGrid() {
for (int i = 0; i < width/cellSize; i++) {
for (int j = 0; j < height/cellSize; j++) {
grid[i][j].show();
}
}
}
void createNewGeneration() {
Cell[][] newGrid = grid.clone();
for (int i = 0; i < width/cellSize; i++) {
for (int j = 0; j < height/cellSize; j++) {
int aliveNeighbours = getAliveNeighbours(i, j);
if (aliveNeighbours == 3) {
newGrid[i][j].alive = true;
} else if (aliveNeighbours < 2 || aliveNeighbours > 3) {
newGrid[i][j].alive = false;
}
}
}
grid = newGrid;
}
int getAliveNeighbours(int x, int y) {
int count = 0;
for (int i = x-1; i <= x+1; i++) {
for (int j = y-1; j <= y+1; j++) {
if (i != x || j != y) {
if (i >= 0 && i < width/cellSize && j >= 0 && j < height/cellSize) {
if (grid[i][j].alive) {
count ++;
}
}
}
}
}
return count;
}
Cell is a simple auxiliary class that I wrote like this:
class Cell {
boolean alive;
int x, y;
Cell(int x, int y, boolean alive) {
this.x = x;
this.y = y;
this.alive = alive;
}
Cell(int x, int y) {
this(x, y, int(random(2)) == 1 ? true : false);
}
void show () {
fill(alive ? 0 : 255);
stroke(200);
rect(x-cellSize/2, y-cellSize/2, cellSize, cellSize);
}
}
The function myInit create a simple “glider” in the grid, which is a spaceship that it’s supposed to keep moving forever, but in my case it becomes a “tub” in like 3 iterations and it stops moving.
Can someone help me understand what I’ve done wrong?
It appears that when you clone an array, you are not creating a new copy of the objects that it contains.
So when you use this line: Cell[][] newGrid = grid.clone(); you are not doing what you think you are doing. You are not creating an array with new Cell having the same value as in grid, you are creating an array where all the values points toward the same Cell object that your created inside your grid. So when you change the Cell in newGrid[i][j] you are also changing the one in grid[i][j] since they are the same object.
I do realize my explanation is not really clear so please consider the following example:
PVector[] array1, array2;
void setup() {
array1 = new PVector[1];
array1[0] = new PVector(10, 10);
println("Array1: x = " + array1[0].x + " ; y = " + array1[0].y);
println("");
println("Copying array1");
array2 = array1.clone();
println("Array2: x = " + array2[0].x + " ; y = " + array2[0].y);
println("");
println("Modifying array2");
array2[0].x = 50;
array2[0].y = 70;
println("Array2: x = " + array2[0].x + " ; y = " + array2[0].y);
println("");
println("We never touched the value of array one and still");
println("Array1: x = " + array1[0].x + " ; y = " + array1[0].y);
}
You can overcome your problem by creating two arrays at the beginning:
Cell[][] grid, newGrid;
int cellSize = 10;
void setup() {
size(800, 800);
grid = new Cell[width/cellSize][height/cellSize];
newGrid = new Cell[width/cellSize][height/cellSize];
myInit();
}
void draw() {
showGrid();
createNewGeneration();
frameRate(2);
}
void myInit() {
int w = width/cellSize;
int h = height/cellSize;
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
grid[i][j] = new Cell(cellSize*i + cellSize/2, cellSize*j + cellSize/2, false);
newGrid[i][j] = new Cell(cellSize*i + cellSize/2, cellSize*j + cellSize/2, false);
}
}
grid[40][40].alive = true;
grid[41][41].alive = true;
grid[41][42].alive = true;
grid[40][42].alive = true;
grid[39][42].alive = true;
}
void showGrid() {
for (int i = 0; i < width/cellSize; i++) {
for (int j = 0; j < height/cellSize; j++) {
grid[i][j].show();
}
}
}
void createNewGeneration() {
for (int i = 0; i < width/cellSize; i++) {
for (int j = 0; j < height/cellSize; j++) {
int aliveNeighbours = getAliveNeighbours(i, j);
//1
if (grid[i][j].alive && aliveNeighbours < 2) {
newGrid[i][j].alive = false;
}
//2
if (grid[i][j].alive && (aliveNeighbours == 2 || aliveNeighbours == 3)) {
newGrid[i][j].alive = true;
}
//3
if (grid[i][j].alive && aliveNeighbours > 3) {
newGrid[i][j].alive = false;
}
//4
if (!grid[i][j].alive && aliveNeighbours == 3) {
newGrid[i][j].alive = true;
}
/*
if (aliveNeighbours == 3) {
newGrid[i][j].alive = true;
} else if (aliveNeighbours < 2 || aliveNeighbours > 3) {
newGrid[i][j].alive = false;
}
*/
}
}
for (int i = 0; i < width/cellSize; i++) {
for (int j = 0; j < height/cellSize; j++) {
grid[i][j].alive = newGrid[i][j].alive;
}
}
}
int getAliveNeighbours(int x, int y) {
int count = 0;
for (int i = x-1; i <= x+1; i++) {
for (int j = y-1; j <= y+1; j++) {
if (i != x || j != y) {
if (i >= 0 && i < width/cellSize && j >= 0 && j < height/cellSize) {
if (grid[i][j].alive) {
count ++;
}
}
}
}
}
return count;
}
class Cell {
boolean alive;
int x, y;
Cell(int x, int y, boolean alive) {
this.x = x;
this.y = y;
this.alive = alive;
}
Cell(int x, int y) {
this(x, y, int(random(2)) == 1 ? true : false);
}
void show () {
fill(alive ? 0 : 255);
stroke(200);
rect(x-cellSize/2, y-cellSize/2, cellSize, cellSize);
}
}