157 lines
3.9 KiB
JavaScript
157 lines
3.9 KiB
JavaScript
// GAME OF LIFE PLUS LANGTON'S ANT
|
|
const sketch = function (p) {
|
|
const gridSize = [200, 200];
|
|
const cellSize = 4;
|
|
const ant_val = 20;
|
|
const game_val = 1;
|
|
const mouse_val = 20;
|
|
const fill_randomly = false;
|
|
const random_fill_value = 1;
|
|
|
|
let agent = { x: cellSize * 30, y: cellSize * 30, angle: 0 };
|
|
let cols, rows;
|
|
let grid = [];
|
|
let nextGrid = [];
|
|
let cActive, cInactive, cAnt;
|
|
|
|
p.setup = function () {
|
|
p.createCanvas(gridSize[0] * cellSize, gridSize[1] * cellSize).parent(
|
|
"sketch"
|
|
);
|
|
cols = p.width / cellSize;
|
|
rows = p.height / cellSize;
|
|
|
|
// Initialize grid
|
|
if (fill_randomly) {
|
|
grid = Array.from({ length: cols }, () =>
|
|
// Array.from => arg1: length of array, arg2: function for each item
|
|
Array.from({ length: rows }, () => ({
|
|
val: p.random() < 0.5 ? random_fill_value : 0,
|
|
}))
|
|
);
|
|
} else {
|
|
grid = Array.from({ length: cols }, () =>
|
|
Array.from({ length: rows }, () => ({ val: 0 }))
|
|
);
|
|
}
|
|
nextGrid = Array.from({ length: cols }, () => Array(rows).fill(0));
|
|
|
|
cActive = p.color(127, 0, 127, 255);
|
|
cInactive = p.color(0, 0, 0, 255);
|
|
cAnt = p.color(0, 255, 255, 255);
|
|
p.background(0);
|
|
p.frameRate(10);
|
|
};
|
|
|
|
p.draw = function () {
|
|
p.noStroke();
|
|
|
|
// Draw the grid
|
|
for (let i = 0; i < cols; i++) {
|
|
for (let j = 0; j < rows; j++) {
|
|
if (grid[i][j].val > 0) {
|
|
const brightness = p.map(grid[i][j].val, 0, ant_val, 50, 255); // Map range t0 50-255
|
|
p.fill(127, 0, brightness, 255);
|
|
} else {
|
|
p.fill(cInactive);
|
|
}
|
|
p.rect(i * cellSize, j * cellSize, cellSize, cellSize);
|
|
}
|
|
}
|
|
p.fill(cAnt);
|
|
p.rect(agent.x, agent.y, cellSize, cellSize);
|
|
|
|
// Langton's Ant logic
|
|
const col = Math.floor(agent.x / cellSize);
|
|
const row = Math.floor(agent.y / cellSize);
|
|
|
|
if (grid[col][row].val > 0) {
|
|
agent.angle += 90;
|
|
grid[col][row].val = 0;
|
|
} else {
|
|
agent.angle -= 90;
|
|
grid[col][row].val = ant_val;
|
|
}
|
|
|
|
agent.angle = (agent.angle + 360) % 360;
|
|
|
|
switch (agent.angle) {
|
|
case 0:
|
|
agent.y -= cellSize;
|
|
break;
|
|
case 90:
|
|
agent.x += cellSize;
|
|
break;
|
|
case 180:
|
|
agent.y += cellSize;
|
|
break;
|
|
case 270:
|
|
agent.x -= cellSize;
|
|
break;
|
|
}
|
|
|
|
agent.x = (agent.x + p.width) % p.width;
|
|
agent.y = (agent.y + p.height) % p.height;
|
|
|
|
// Game of Life logic
|
|
for (let i = 0; i < cols; i++) {
|
|
for (let j = 0; j < rows; j++) {
|
|
const neighbors = countNeighbors(i, j);
|
|
|
|
if (grid[i][j].val > 0) {
|
|
switch (neighbors) {
|
|
case 2:
|
|
case 3:
|
|
nextGrid[i][j] = grid[i][j].val;
|
|
break;
|
|
default:
|
|
nextGrid[i][j] = grid[i][j].val - 1;
|
|
break;
|
|
}
|
|
} else {
|
|
if (neighbors === 3) {
|
|
nextGrid[i][j] = game_val;
|
|
} else {
|
|
nextGrid[i][j] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Swap grids
|
|
for (let i = 0; i < cols; i++) {
|
|
for (let j = 0; j < rows; j++) {
|
|
grid[i][j].val = nextGrid[i][j];
|
|
}
|
|
}
|
|
};
|
|
|
|
function countNeighbors(x, y) {
|
|
let count = 0;
|
|
for (let i = -1; i <= 1; i++) {
|
|
for (let j = -1; j <= 1; j++) {
|
|
if (i === 0 && j === 0) continue;
|
|
const col = (x + i + cols) % cols;
|
|
const row = (y + j + rows) % rows;
|
|
count += grid[col][row].val > 0 ? 1 : 0;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
p.mouseClicked = function () {
|
|
const x = Math.floor(p.mouseX / cellSize);
|
|
const y = Math.floor(p.mouseY / cellSize);
|
|
if (x >= 0 && x < cols && y >= 0 && y < rows) {
|
|
grid[x][y].val = grid[x][y].val > 0 ? 0 : mouse_val;
|
|
}
|
|
};
|
|
|
|
p.keyPressed = function () {
|
|
if (p.keyCode === 32) {
|
|
p.isLooping() ? p.noLoop() : p.loop();
|
|
}
|
|
};
|
|
};
|
|
|
|
new p5(sketch);
|