I'm working on some code for a javascript implemenation of Conway's Game of Life Cellular Automata for a personal project, and I've reached the point of encoding the rules. I am applying the rules to each cell, then storing the new version in a copy of the grid. Then, when I'm finished calculating each cell's next state, I set the first grid's state to the second's one, empty the second grid, and start over. Here's the code I used for the rules:
//10x10 grid
let ecells = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
let cells = empty_cells;
let new_cells = cells;
let paused = true;
function Cell(x, y) {
return cells[y][x];
}
function Nsum(i, j) {
if (i >= 1 && j >= 1) {
return Cell(i - 1, j) + Cell(i + 1, j) + Cell(i, j - 1) + Cell(i - 1, j - 1) + Cell(i + 1, j - 1) + Cell(i, j + 1) + Cell(i - 1, j + 1) + Cell(i + 1, j + 1);
}
}
//One can manually change the state of the cells in the "cells" grid,
//which works correctly. Then, one can run the CA by changing the "paused"
//value to false.
function simulation() {
for (i = 0; i < cells[0].length; i++) {
for (j = 0; j < cells.length; j++) {
if (Cell(i, j)) {
ctx.fillRect(20*i - 0.5, 20*j, 20, 20);
if (!paused) {
if (Nsum(i, j) == 2 || Nsum(i, j) == 3) new_cells[j][i] = 1;
else new_cells[j][i] = 0;
}
}
else {
ctx.clearRect(20*i - 0.5, 20*j, 20, 20);
if (!paused) {
if (Nsum(i, j) == 3) new_cells[j][i] = 1;
else new_cells[j][i] = 0;
}
}
}
}
if (!paused) cells = new_cells;
new_cells = empty_cells;
requestAnimationFrame(simulation);
}
simulation();
The rule logic is inside the nested for loop, Nsum is the function that calculates the neighborhood sum of the current cell. I say ncells[j][i] instead of ncells[i][j] because in a 2d array you address the row first.
I didn't try much, but I can't imagine a solution. Help!
Let's start by not bothering with rows vs. columns, because (and this is the nice thing about the game of life), it doesn't matter. The only thing that matters is what the eight values around a cell are doing, so as long as we stick to one ordering, the code will simply do the right thing.
Which means we can get rid of that
Cellfunction (on that note, that's not how you name things in JS. Variables and functions use lowerCamelCase, classes/constructor functions use UpperCamelCase and constant values use UPPER_SNAKE_CASE).Then, let's fix
Nsumbecause it's ignoring the edges right now, which is not how the game of life works: in order to count how many neighbours a cell has, we need to sum up to eight values, but not every cell has eight neighbours. For instance, (0,0) has nothing to the left/above it. So let's rewrite that to a loop:We can also take advantage of the fact that we know that we're setting our update board to zeroes before we start calculating updates, so we don't need to set any cells to 0: they already are.
So if we put all that together, and instead of using a canvas we just use a preformatted HTML element that we print our grid into, we get: