xxxxxxxxxx
316
let playing = false;
let sandbox = false;
let allowInput = false;
let rows;
let columns;
let grid = [];
let born = [3];
let survive = [2, 3];
let level = -1;
let goalGrid = [];
let playerGrid;
let generationCount = 0;
function setup() {
const canvas = createCanvas(400, 400);
canvas.parent("sketch");
noSmooth();
nextLevel();
}
function draw() {
background(255);
const cellWidth = width / columns;
const cellHeight = height / rows;
for (let r = 0; r < rows; r++) {
for (let c = 0; c < columns; c++) {
const cellX = c * cellWidth;
const cellY = r * cellHeight;
strokeWeight(2);
stroke(32);
if (grid[r][c]) {
fill(32);
} else {
noFill();
}
rect(cellX + 2, cellY + 2, cellWidth - 4, cellHeight - 4);
}
}
if (playing && frameCount % 60 == 0) {
nextGeneration();
}
}
function nextGeneration() {
const nextGrid = [];
for (let r = 0; r < rows; r++) {
nextGrid[r] = [];
}
for (let r = 0; r < rows; r++) {
for (let c = 0; c < columns; c++) {
const neighbors = countNeighbors(r, c);
if (grid[r][c] && survive.includes(neighbors)) {
nextGrid[r][c] = true;
} else if (!grid[r][c] && born.includes(neighbors)) {
nextGrid[r][c] = true;
}
}
}
if(!sandbox && !checkGridChanged(nextGrid)){
select('#lose-div').removeClass('hidden');
select('#hint').html('<strong>Hint:</strong> ' + levelHints[level]);
}
grid = nextGrid;
generationCount++;
select('#generation').html('Generation: ' + generationCount);
if (!sandbox && generationCount == levelGenerations[level]) {
if (checkWin()) {
playing = false;
select('#game-controls').addClass('hidden');
if (level == levelSizes.length - 1) {
select('#final-win-div').removeClass('hidden');
} else {
select('#win-div').removeClass('hidden');
}
} else {
playing = false;
select('#game-controls').addClass('hidden');
select('#lose-div').removeClass('hidden');
select('#hint').html('<strong>Hint:</strong> ' + levelHints[level]);
}
}
}
function countNeighbors(r, c) {
let count = 0;
for (let dr = -1; dr <= 1; dr++) {
for (let dc = -1; dc <= 1; dc++) {
if (dr == 0 && dc == 0) {
continue;
}
if (r + dr < 0 || r + dr >= rows ||
c + dc < 0 || c + dc >= columns) {
continue;
}
if (grid[r + dr][c + dc]) {
count++;
}
}
}
return count;
}
function play() {
frameCount = 0;
generationCount = 0;
select('#generation').html('Generation: ' + generationCount);
select('#game-controls').addClass('hidden');
select('#win-div').addClass('hidden');
select('#lose-div').addClass('hidden');
playing = true;
allowInput = false;
playerGrid = grid;
nextGeneration();
}
function playSandbox(){
playing = true;
nextGeneration();
}
function checkWin() {
for (let r = 0; r < rows; r++) {
for (let c = 0; c < columns; c++) {
if (grid[r][c] != goalGrid[r][c]) {
return false;
}
}
}
return true;
}
function checkGridChanged(nextGrid){
for (let r = 0; r < rows; r++) {
for (let c = 0; c < columns; c++) {
if (grid[r][c] != nextGrid[r][c]) {
return true;
}
}
}
return false;
}
function nextLevel() {
level++;
generationCount = 0;
select('#generation').html('Generation: ' + generationCount);
rows = levelSizes[level].rows;
columns = levelSizes[level].columns;
setRules();
setGrid();
setGoalGrid();
allowInput = true;
playerGrid = undefined;
select('#win-div').addClass('hidden');
select('#game-controls').removeClass('hidden');
select('#level-title').html('Level ' + (level+1));
select('#level-description')
.html('<strong>Goal:</strong> ' +
'Reach this pattern in <strong>' +
levelGenerations[level] +
(levelGenerations[level] > 1 ? ' generations.' : ' generation.') +
'</strong>');
if (level == 1) {
select('#start-instructions').addClass('hidden');
}
}
function setRules() {
setRulesText();
}
function setRulesText() {
let s = '<strong>Rules:</strong>';
s += '<br>';
if (born.length) {
s += 'Dead cells with <strong>' +
getNeighborsCountText(born) +
'</strong> are born.';
s += '<br>'
}
if (survive.length) {
s += 'Alive cells with <strong>' +
getNeighborsCountText(survive) +
'</strong> survive.';
}
select('#rules').html(s);
}
function getNeighborsCountText(neighborsCountArray) {
if (neighborsCountArray.length == 1) {
if (neighborsCountArray[0] == 1) {
return '1 neighbor';
}
return neighborsCountArray[0] + ' neighbors';
} else if (neighborsCountArray.length == 2) {
return neighborsCountArray[0] + ' or ' + neighborsCountArray[1] + ' neighbors';
}
let s = '';
for (let i = 0; i < neighborsCountArray.length; i++) {
s += neighborsCountArray[i];
if (i < neighborsCountArray.length - 2) {
s += ', ';
} else if (i == neighborsCountArray.length - 2) {
s += ', or ';
}
}
s += ' neighbors';
return s;
}
function restartLevel(){
clearGrid();
select('#lose-div').addClass('hidden');
select('#game-controls').removeClass('hidden');
playing = false;
allowInput = true;
if(playerGrid){
grid = playerGrid;
}
}
function clearGrid() {
setGrid();
generationCount = 0;
select('#generation').html('Generation: ' + generationCount);
}
function setGrid() {
grid = [];
for (let r = 0; r < rows; r++) {
grid[r] = [];
}
}
function setGoalGrid() {
goalGrid = [];
for (let r = 0; r < rows; r++) {
goalGrid[r] = [];
}
for (const cell of levelGoals[level]) {
goalGrid[cell.r][cell.c] = true;
}
goalP5.loop();
}
function step() {
nextGeneration();
playing = false;
}
function startSandbox() {
sandbox = true;
allowInput = true;
select('#level-title').html('Sandbox Mode!');
select('#level-description').addClass('hidden');
select('#game-controls').addClass('hidden');
select('#final-win-div').addClass('hidden');
select('#sandbox-controls').removeClass('hidden');
select('#goal-sketch').addClass('hidden');
}
function setGridSize() {
const gridSize = select('#grid-size').value();
rows = gridSize;
columns = gridSize;
setGrid();
}
function mousePressed() {
if (sandbox || allowInput) {
const r = Math.floor(rows * mouseY / height);
const c = Math.floor(columns * mouseX / width);
if (r >= 0 && r < rows && c >= 0 && c < columns) {
grid[r][c] = !grid[r][c];
}
playing = false;
}
}
function printGrid() {
let s = '[';
for (let r = 0; r < rows; r++) {
for (let c = 0; c < columns; c++) {
if (grid[r][c]) {
s += '{r:' + r + ',c:' + c + '},'
}
}
}
s += ']';
console.log(s);
}