Skip to content

Instantly share code, notes, and snippets.

@cravelweb
Last active November 10, 2024 13:13
Show Gist options
  • Save cravelweb/9a5661d339100007614441de4624ae22 to your computer and use it in GitHub Desktop.
Save cravelweb/9a5661d339100007614441de4624ae22 to your computer and use it in GitHub Desktop.
Conway's Game of Life JavaScript - ライフゲーム.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game of Life</title>
<style>
canvas {
border: 1px solid black;
display: block;
margin: 20px auto;
cursor: crosshair;
}
#controls {
text-align: center;
margin: 10px auto;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="800" height="800"></canvas>
<div id="controls">
<button id="startStopButton">Play</button>
<button id="clearButton">Clear</button>
<button id="randomButton">Random Setup</button>
<label for="speedRange">Speed:</label>
<input type="range" id="speedRange" min="10" max="1000" value="100">
<label for="patternSelect">Pattern:</label>
<select id="patternSelect">
<option value="cell">cell</option>
<option value="random">random</option>
<option value="gliderGun">Glider Gun</option>
<option value="pufferTrain">Puffer Train</option>
<option value="glider">Glider</option>
<option value="lightweightSpaceship">Lightweight Spaceship</option>
</select>
</div>
<script src="life-game.js"></script>
</body>
</html>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const gridSize = 100;
const cellSize = canvas.width / gridSize;
let grid = createGrid(gridSize);
let isRunning = false;
let intervalId;
let speed = 100;
let isMouseDown = false;
// Initialize with random setup
initializeRandomGrid();
// Get control elements
const startStopButton = document.getElementById('startStopButton');
const clearButton = document.getElementById('clearButton');
const randomButton = document.getElementById('randomButton');
const speedRange = document.getElementById('speedRange');
const patternSelect = document.getElementById('patternSelect');
// Event listener for play/stop button
startStopButton.addEventListener('click', () => {
if (isRunning) {
stopGame();
} else {
startGame();
}
});
// Event listener for clear button
clearButton.addEventListener('click', () => {
stopGame();
grid = createGrid(gridSize);
drawGrid(grid);
});
// Event listener for random setup button
randomButton.addEventListener('click', () => {
stopGame();
initializeRandomGrid();
drawGrid(grid);
});
// Event listener for speed slider
speedRange.addEventListener('input', (event) => {
speed = event.target.value;
if (isRunning) {
stopGame();
startGame();
}
});
// Function to start the game
function startGame() {
isRunning = true;
startStopButton.textContent = 'Stop';
intervalId = setInterval(() => {
drawGrid(grid);
grid = nextGeneration(grid);
}, speed);
}
// Function to stop the game
function stopGame() {
isRunning = false;
startStopButton.textContent = 'Play';
clearInterval(intervalId);
}
// Function to draw the grid
function drawGrid(grid) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < gridSize; i++) {
for (let j = 0; j < gridSize; j++) {
if (grid[i][j] === 1) {
ctx.fillStyle = 'black';
ctx.fillRect(i * cellSize, j * cellSize, cellSize, cellSize);
}
}
}
}
// Function to calculate the next generation of the grid
function nextGeneration(grid) {
let newGrid = createGrid(gridSize);
for (let i = 0; i < gridSize; i++) {
for (let j = 0; j < gridSize; j++) {
const aliveNeighbors = countAliveNeighbors(grid, i, j);
if (grid[i][j] === 1) {
newGrid[i][j] = (aliveNeighbors === 2 || aliveNeighbors === 3) ? 1 : 0;
} else {
newGrid[i][j] = (aliveNeighbors === 3) ? 1 : 0;
}
}
}
return newGrid;
}
// Function to count the number of alive neighbors of a cell
function countAliveNeighbors(grid, 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; // Skip the cell itself
const nx = (x + i + gridSize) % gridSize; // Wrap around the edges
const ny = (y + j + gridSize) % gridSize; // Wrap around the edges
count += grid[nx][ny];
}
}
return count;
}
// Function to initialize the grid
function createGrid(size) {
let grid = new Array(size);
for (let i = 0; i < size; i++) {
grid[i] = new Array(size).fill(0);
}
return grid;
}
// Function to initialize the grid with random cells
function initializeRandomGrid() {
grid = createGrid(gridSize);
for (let i = 0; i < gridSize; i++) {
for (let j = 0; j < gridSize; j++) {
grid[i][j] = Math.random() > 0.8 ? 1 : 0;
}
}
}
// Function to place a specific pattern on the grid
function placePattern(pattern, offsetX, offsetY) {
pattern.forEach(([x, y]) => {
const gridX = (x + offsetX) % gridSize;
const gridY = (y + offsetY) % gridSize;
grid[gridX][gridY] = 1;
});
}
// Event listener for mouse actions to handle cell placement
canvas.addEventListener('mousedown', () => {
isMouseDown = true;
});
canvas.addEventListener('mouseup', () => {
isMouseDown = false;
});
canvas.addEventListener('mousemove', (event) => {
if (isMouseDown) {
handlePatternPlacement(event);
}
});
canvas.addEventListener('click', (event) => {
handlePatternPlacement(event);
});
// Function to handle pattern placement based on mouse click
function handlePatternPlacement(event) {
const rect = canvas.getBoundingClientRect();
const scaleX = canvas.width / rect.width;
const scaleY = canvas.height / rect.height;
const x = Math.floor((event.clientX - rect.left) * scaleX / cellSize);
const y = Math.floor((event.clientY - rect.top) * scaleY / cellSize);
if (x >= 0 && x < gridSize && y >= 0 && y < gridSize) {
const selectedPattern = patternSelect.value;
if (selectedPattern === 'cell') {
grid[x][y] = grid[x][y] === 1 ? 0 : 1; // Toggle cell
} else if (selectedPattern === 'random') {
for (let i = -5; i <= 5; i++) {
for (let j = -5; j <= 5; j++) {
const nx = (x + i + gridSize) % gridSize;
const ny = (y + j + gridSize) % gridSize;
if (Math.random() > 0.5) {
grid[nx][ny] = 1;
}
}
}
} else if (selectedPattern === 'gliderGun') {
placePattern(gliderGunPattern, x, y);
} else if (selectedPattern === 'pufferTrain') {
placePattern(pufferTrainPattern, x, y);
} else if (selectedPattern === 'glider') {
placePattern(gliderPattern, x, y);
} else if (selectedPattern === 'lightweightSpaceship') {
placePattern(lightweightSpaceshipPattern, x, y);
}
drawGrid(grid);
}
}
// Definition of patterns
const gliderGunPattern = [
[0, 4], [1, 4], [1, 5], [0, 5], [10, 4], [10, 5], [10, 6],
[11, 3], [11, 7], [12, 2], [12, 8], [13, 2], [13, 8], [14, 5],
[15, 3], [15, 7], [16, 4], [16, 5], [16, 6], [17, 5], [20, 2],
[20, 3], [20, 4], [21, 2], [21, 3], [21, 4], [22, 1], [22, 5],
[24, 0], [24, 1], [24, 5], [24, 6], [34, 2], [34, 3], [35, 2],
[35, 3]
];
const pufferTrainPattern = [
[0, 0], [1, 1], [1, 2], [2, 2], [2, 3], [3, 3], [4, 3],
[5, 2], [5, 1], [6, 1], [6, 0], [7, 0], [8, 0], [9, 0]
];
const gliderPattern = [
[0, 1], [1, 2], [2, 0], [2, 1], [2, 2]
];
const lightweightSpaceshipPattern = [
[0, 1], [0, 4], [1, 0], [2, 0], [3, 0], [3, 4], [4, 0],
[4, 1], [4, 2], [4, 3]
];
// Initial drawing of the grid
drawGrid(grid);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment