xxxxxxxxxx
389
let grid;
let nextGrid;
let cellSize = 10;
let cols, rows;
let isPaused = true;
let isStepMode = false;
let brushSize = 1;
let aliveColor;
let deadColor;
let pauseButton;
let stepButton;
let populationCount = 0;
let populationHistory = [];
let maxHistoryLength = 100;
let sliderLabels = {};
let defaultSettings = {
birthRule: 3,
survivalMin: 2,
survivalMax: 3,
brushSize: 1,
aliveColor: '#FF5733',
deadColor: '#1A1A1A'
};
let rules = {defaultSettings};
function setup() {
createCanvas(800, 600);
cols = floor(width / cellSize);
rows = floor(height / cellSize);
// Create main container
let mainContainer = createDiv('');
mainContainer.style('display', 'flex');
mainContainer.style('gap', '20px');
mainContainer.style('margin-bottom', '20px');
// Create control container
let controlDiv = createDiv('');
controlDiv.parent(mainContainer);
controlDiv.style('padding', '10px');
controlDiv.style('background-color', '#f0f0f0');
controlDiv.style('flex', '1');
// Create stats container
let statsDiv = createDiv('');
statsDiv.parent(mainContainer);
statsDiv.style('padding', '10px');
statsDiv.style('background-color', '#f0f0f0');
statsDiv.style('width', '200px');
// Population stats
statsDiv.child(createP('Population Statistics:').style('font-weight', 'bold'));
let popCount = createP('Current Population: 0');
statsDiv.child(popCount);
// Update population count every frame
setInterval(() => {
populationCount = countPopulation();
popCount.html('Current Population: ' + populationCount);
// Update history
populationHistory.push(populationCount);
if (populationHistory.length > maxHistoryLength) {
populationHistory.shift();
}
}, 100);
// Initialize color pickers
controlDiv.child(createP('Alive Cell Color:'));
let colorPicker1 = createColorPicker(defaultSettings.aliveColor);
controlDiv.child(colorPicker1);
controlDiv.child(createP('Dead Cell Color:'));
let colorPicker2 = createColorPicker(defaultSettings.deadColor);
controlDiv.child(colorPicker2);
// Initialize sliders with labels
let birthContainer = createDiv('');
birthContainer.parent(controlDiv);
birthContainer.style('display', 'flex');
birthContainer.style('align-items', 'center');
birthContainer.style('margin', '10px 0');
birthContainer.child(createP('Birth Rule (neighbors needed): '));
let birthSlider = createSlider(1, 8, defaultSettings.birthRule, 1);
birthContainer.child(birthSlider);
sliderLabels.birth = createSpan(defaultSettings.birthRule);
sliderLabels.birth.parent(birthContainer);
sliderLabels.birth.style('margin-left', '10px');
let survivalMinContainer = createDiv('');
survivalMinContainer.parent(controlDiv);
survivalMinContainer.style('display', 'flex');
survivalMinContainer.style('align-items', 'center');
survivalMinContainer.style('margin', '10px 0');
survivalMinContainer.child(createP('Survival Min: '));
let survivalMinSlider = createSlider(1, 8, defaultSettings.survivalMin, 1);
survivalMinContainer.child(survivalMinSlider);
sliderLabels.survivalMin = createSpan(defaultSettings.survivalMin);
sliderLabels.survivalMin.parent(survivalMinContainer);
sliderLabels.survivalMin.style('margin-left', '10px');
let survivalMaxContainer = createDiv('');
survivalMaxContainer.parent(controlDiv);
survivalMaxContainer.style('display', 'flex');
survivalMaxContainer.style('align-items', 'center');
survivalMaxContainer.style('margin', '10px 0');
survivalMaxContainer.child(createP('Survival Max: '));
let survivalMaxSlider = createSlider(1, 8, defaultSettings.survivalMax, 1);
survivalMaxContainer.child(survivalMaxSlider);
sliderLabels.survivalMax = createSpan(defaultSettings.survivalMax);
sliderLabels.survivalMax.parent(survivalMaxContainer);
sliderLabels.survivalMax.style('margin-left', '10px');
let brushContainer = createDiv('');
brushContainer.parent(controlDiv);
brushContainer.style('display', 'flex');
brushContainer.style('align-items', 'center');
brushContainer.style('margin', '10px 0');
brushContainer.child(createP('Brush Size: '));
let brushSlider = createSlider(1, 5, defaultSettings.brushSize, 1);
brushContainer.child(brushSlider);
sliderLabels.brush = createSpan(defaultSettings.brushSize);
sliderLabels.brush.parent(brushContainer);
sliderLabels.brush.style('margin-left', '10px');
// Create button container
let buttonDiv = createDiv('');
buttonDiv.style('margin-top', '10px');
controlDiv.child(buttonDiv);
// Create mode container
let modeDiv = createDiv('');
modeDiv.style('margin-bottom', '10px');
buttonDiv.child(modeDiv);
// Create checkbox for step mode
let stepModeCheckbox = createCheckbox('Step-by-Step Mode', false);
stepModeCheckbox.parent(modeDiv);
stepModeCheckbox.changed(() => {
isStepMode = stepModeCheckbox.checked();
if (isStepMode) {
isPaused = true;
pauseButton.html('Start Simulation');
stepButton.removeAttribute('disabled');
} else {
stepButton.attribute('disabled', '');
}
});
// Create buttons
pauseButton = createButton('Start Simulation');
pauseButton.class('control-button');
pauseButton.style('margin-right', '10px');
pauseButton.mousePressed(togglePause);
buttonDiv.child(pauseButton);
stepButton = createButton('Step Forward');
stepButton.class('control-button');
stepButton.style('margin-right', '10px');
stepButton.attribute('disabled', '');
stepButton.mousePressed(() => {
if (isStepMode) {
updateGrid();
}
});
buttonDiv.child(stepButton);
let clearButton = createButton('Clear Grid');
clearButton.class('control-button');
clearButton.style('margin-right', '10px');
clearButton.mousePressed(clearGrid);
buttonDiv.child(clearButton);
let randomButton = createButton('Random Pattern');
randomButton.class('control-button');
randomButton.style('margin-right', '10px');
randomButton.mousePressed(randomizeGrid);
buttonDiv.child(randomButton);
let resetButton = createButton('Reset Settings');
resetButton.class('control-button');
resetButton.mousePressed(() => {
birthSlider.value(defaultSettings.birthRule);
survivalMinSlider.value(defaultSettings.survivalMin);
survivalMaxSlider.value(defaultSettings.survivalMax);
brushSlider.value(defaultSettings.brushSize);
colorPicker1.value(defaultSettings.aliveColor);
colorPicker2.value(defaultSettings.deadColor);
rules = {defaultSettings};
aliveColor = color(defaultSettings.aliveColor);
deadColor = color(defaultSettings.deadColor);
brushSize = defaultSettings.brushSize;
updateAllLabels();
});
buttonDiv.child(resetButton);
// Add some CSS styles
let style = document.createElement('style');
style.textContent = `
.control-button {
padding: 8px 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-bottom: 5px;
}
.control-button:hover:not([disabled]) {
background-color: #45a049;
}
.control-button[disabled] {
background-color: #cccccc;
cursor: not-allowed;
}
`;
document.head.appendChild(style);
// Initialize grids
grid = make2DArray(cols, rows);
nextGrid = make2DArray(cols, rows);
clearGrid();
// Update functions for interactive elements
colorPicker1.input(() => aliveColor = colorPicker1.color());
colorPicker2.input(() => deadColor = colorPicker2.color());
birthSlider.input(() => {
rules.birthRule = birthSlider.value();
sliderLabels.birth.html(rules.birthRule);
});
survivalMinSlider.input(() => {
rules.survivalMin = survivalMinSlider.value();
sliderLabels.survivalMin.html(rules.survivalMin);
});
survivalMaxSlider.input(() => {
rules.survivalMax = survivalMaxSlider.value();
sliderLabels.survivalMax.html(rules.survivalMax);
});
brushSlider.input(() => {
brushSize = brushSlider.value();
sliderLabels.brush.html(brushSize);
});
aliveColor = colorPicker1.color();
deadColor = colorPicker2.color();
}
function countPopulation() {
let count = 0;
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
if (grid[i][j] === 1) count++;
}
}
return count;
}
function updateAllLabels() {
sliderLabels.birth.html(rules.birthRule);
sliderLabels.survivalMin.html(rules.survivalMin);
sliderLabels.survivalMax.html(rules.survivalMax);
sliderLabels.brush.html(brushSize);
}
function draw() {
background(deadColor);
// Draw current grid
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
let x = i * cellSize;
let y = j * cellSize;
if (grid[i][j] === 1) {
fill(aliveColor);
noStroke();
rect(x, y, cellSize, cellSize);
}
}
}
// Draw grid lines when paused or in step mode
if (isPaused || isStepMode) {
stroke(128, 128, 128, 100);
strokeWeight(0.5);
for (let i = 0; i <= cols; i++) {
line(i * cellSize, 0, i * cellSize, height);
}
for (let j = 0; j <= rows; j++) {
line(0, j * cellSize, width, j * cellSize);
}
}
// Update grid if not paused and not in step mode
if (!isPaused && !isStepMode) {
updateGrid();
}
// Handle mouse interaction
if (mouseIsPressed && mouseX >= 0 && mouseX < width && mouseY >= 0 && mouseY < height) {
let i = floor(mouseX / cellSize);
let j = floor(mouseY / cellSize);
// Draw with brush size
for (let di = -brushSize + 1; di < brushSize; di++) {
for (let dj = -brushSize + 1; dj < brushSize; dj++) {
let ni = i + di;
let nj = j + dj;
if (ni >= 0 && ni < cols && nj >= 0 && nj < rows) {
grid[ni][nj] = mouseButton === LEFT ? 1 : 0;
}
}
}
}
}
function togglePause() {
if (!isStepMode) {
isPaused = !isPaused;
pauseButton.html(isPaused ? 'Start Simulation' : 'Pause Simulation');
}
}
function make2DArray(cols, rows) {
let arr = new Array(cols);
for (let i = 0; i < cols; i++) {
arr[i] = new Array(rows).fill(0);
}
return arr;
}
function randomizeGrid() {
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
grid[i][j] = random() < 0.2 ? 1 : 0;
}
}
}
function clearGrid() {
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
grid[i][j] = 0;
}
}
populationHistory = [];
}
function countNeighbors(grid, x, y) {
let sum = 0;
for (let i = -1; i < 2; i++) {
for (let j = -1; j < 2; j++) {
let col = (x + i + cols) % cols;
let row = (y + j + rows) % rows;
sum += grid[col][row];
}
}
sum -= grid[x][y];
return sum;
}
function updateGrid() {
// Create next generation based on current rules
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
let neighbors = countNeighbors(grid, i, j);
let state = grid[i][j];
// Apply rules
if (state === 0 && neighbors === rules.birthRule) {
nextGrid[i][j] = 1;
} else if (state === 1 && (neighbors >= rules.survivalMin && neighbors <= rules.survivalMax)) {
nextGrid[i][j] = 1;
} else {
nextGrid[i][j] = 0;
}
}
}
// Swap grids
let temp = grid;
grid = nextGrid;
nextGrid = temp;
}