Let's get counting live neighbors into it's own function. In the one below, I loop a little differently so you don't have to include all those if statements. It gets any cell within one distance away in any direction, excluding the cell itself.
function getLiveNeighborCount (row, col) {
let result = 0;
let rLow = row == 0 ? 0 : row - 1;
let rHigh = row == model.length -1 ? row : row + 1;
for (let r = rLow; r <= rHigh; r++) {
let cLow = col == 0 ? 0 : col - 1;
let cHigh = col == model[r].length -1 ? col : col + 1;
for (let c = cLow; c <= cHigh; c++)
if (r != 0 || c != 0)
result += model[r][c];
}
return result;
}
Now shouldBeAlive() just cares about your rules:
function shouldBeAlive (row, col) {
var alive = model[row][col];
var lnc = getLiveNeighborCount(row, col);
return (
!alive && lnc != 3 ? false
: lnc == 2 || lnc == 3 ? true
: false
);
}
By the way. You may want to prevent execution of shouldBeAlive before all "should" calculations occur. I say this because I don't imagine that a cell to the upper-left should get priority over one in the lower-right. They should all get their value simultaneously. So consider changing your evolve function to something like this:
function evolve() {
let anticipated = [];
for (let r = 0; r < model.length; r++) {
anticipated[r] = [];
for (let c = 0; c < model[r].length; c++)
anticipated[r][c] = shouldBeAlive(r,c);
}
model = anticipated;
paintGrid();
}