Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>Conway's Game of Life</title> | |
| <style> | |
| body { | |
| margin: 0; | |
| font-family: Arial, sans-serif; | |
| background: #111827; | |
| color: white; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| min-height: 100vh; | |
| } | |
| h1 { | |
| margin: 20px 0 5px; | |
| font-size: 2rem; | |
| } | |
| p { | |
| margin: 0 0 15px; | |
| color: #cbd5e1; | |
| text-align: center; | |
| max-width: 800px; | |
| } | |
| .stats { | |
| display: flex; | |
| gap: 20px; | |
| margin-bottom: 12px; | |
| font-size: 1rem; | |
| color: #e5e7eb; | |
| } | |
| canvas { | |
| background: #0f172a; | |
| border: 2px solid #334155; | |
| border-radius: 12px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.35); | |
| cursor: pointer; | |
| } | |
| .controls { | |
| margin: 18px 0; | |
| display: flex; | |
| flex-wrap: wrap; | |
| justify-content: center; | |
| gap: 10px; | |
| max-width: 900px; | |
| } | |
| button, select, input { | |
| border: none; | |
| border-radius: 10px; | |
| padding: 10px 14px; | |
| font-size: 0.95rem; | |
| } | |
| button { | |
| background: #2563eb; | |
| color: white; | |
| cursor: pointer; | |
| transition: transform 0.15s, background 0.15s; | |
| } | |
| button:hover { | |
| background: #1d4ed8; | |
| transform: translateY(-1px); | |
| } | |
| select, input { | |
| background: #e5e7eb; | |
| color: #111827; | |
| } | |
| label { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| background: #1e293b; | |
| padding: 6px 10px; | |
| border-radius: 10px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>Conway's Game of Life</h1> | |
| <p>Click cells to toggle life. Press Play and watch simple rules create complex patterns.</p> | |
| <div class="stats"> | |
| <div>Generation: <span id="generation">0</span></div> | |
| <div>Live Cells: <span id="liveCells">0</span></div> | |
| </div> | |
| <canvas id="gameCanvas" width="800" height="500"></canvas> | |
| <div class="controls"> | |
| <button onclick="play()">Play</button> | |
| <button onclick="pause()">Pause</button> | |
| <button onclick="step()">Step</button> | |
| <button onclick="resetGrid()">Reset</button> | |
| <button onclick="randomizeGrid()">Randomize</button> | |
| <select id="patternSelect" onchange="loadPattern(this.value)"> | |
| <option value="">Choose Pattern</option> | |
| <option value="glider">Glider</option> | |
| <option value="pulsar">Pulsar</option> | |
| <option value="spaceship">Lightweight Spaceship</option> | |
| <option value="gosper">Gosper Glider Gun</option> | |
| </select> | |
| <label> | |
| Speed | |
| <input id="speed" type="range" min="50" max="800" value="200" oninput="changeSpeed()" /> | |
| </label> | |
| </div> | |
| <script> | |
| const canvas = document.getElementById('gameCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const generationEl = document.getElementById('generation'); | |
| const liveCellsEl = document.getElementById('liveCells'); | |
| const speedInput = document.getElementById('speed'); | |
| const cellSize = 10; | |
| const cols = Math.floor(canvas.width / cellSize); | |
| const rows = Math.floor(canvas.height / cellSize); | |
| let grid = createGrid(); | |
| let generation = 0; | |
| let timer = null; | |
| let speed = 200; | |
| function createGrid() { | |
| return Array.from({ length: rows }, () => Array(cols).fill(0)); | |
| } | |
| function drawGrid() { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| let liveCount = 0; | |
| for (let r = 0; r < rows; r++) { | |
| for (let c = 0; c < cols; c++) { | |
| if (grid[r][c]) { | |
| ctx.fillStyle = '#38bdf8'; | |
| ctx.fillRect(c * cellSize, r * cellSize, cellSize - 1, cellSize - 1); | |
| liveCount++; | |
| } else { | |
| ctx.fillStyle = '#020617'; | |
| ctx.fillRect(c * cellSize, r * cellSize, cellSize - 1, cellSize - 1); | |
| } | |
| } | |
| } | |
| generationEl.textContent = generation; | |
| liveCellsEl.textContent = liveCount; | |
| } | |
| function countNeighbors(row, col) { | |
| let count = 0; | |
| for (let dr = -1; dr <= 1; dr++) { | |
| for (let dc = -1; dc <= 1; dc++) { | |
| if (dr === 0 && dc === 0) continue; | |
| const r = row + dr; | |
| const c = col + dc; | |
| if (r >= 0 && r < rows && c >= 0 && c < cols) { | |
| count += grid[r][c]; | |
| } | |
| } | |
| } | |
| return count; | |
| } | |
| function nextGeneration() { | |
| const next = createGrid(); | |
| for (let r = 0; r < rows; r++) { | |
| for (let c = 0; c < cols; c++) { | |
| const neighbors = countNeighbors(r, c); | |
| const alive = grid[r][c] === 1; | |
| if (alive && (neighbors === 2 || neighbors === 3)) { | |
| next[r][c] = 1; | |
| } else if (!alive && neighbors === 3) { | |
| next[r][c] = 1; | |
| } | |
| } | |
| } | |
| grid = next; | |
| generation++; | |
| drawGrid(); | |
| } | |
| function play() { | |
| if (!timer) { | |
| timer = setInterval(nextGeneration, speed); | |
| } | |
| } | |
| function pause() { | |
| clearInterval(timer); | |
| timer = null; | |
| } | |
| function step() { | |
| pause(); | |
| nextGeneration(); | |
| } | |
| function resetGrid() { | |
| pause(); | |
| grid = createGrid(); | |
| generation = 0; | |
| document.getElementById('patternSelect').value = ''; | |
| drawGrid(); | |
| } | |
| function randomizeGrid() { | |
| pause(); | |
| grid = createGrid().map(row => row.map(() => Math.random() > 0.75 ? 1 : 0)); | |
| generation = 0; | |
| drawGrid(); | |
| } | |
| function changeSpeed() { | |
| speed = Number(speedInput.value); | |
| if (timer) { | |
| pause(); | |
| play(); | |
| } | |
| } | |
| canvas.addEventListener('click', event => { | |
| const rect = canvas.getBoundingClientRect(); | |
| const col = Math.floor((event.clientX - rect.left) / cellSize); | |
| const row = Math.floor((event.clientY - rect.top) / cellSize); | |
| if (row >= 0 && row < rows && col >= 0 && col < cols) { | |
| grid[row][col] = grid[row][col] ? 0 : 1; | |
| drawGrid(); | |
| } | |
| }); | |
| function placePattern(pattern, startRow, startCol) { | |
| grid = createGrid(); | |
| generation = 0; | |
| pattern.forEach(([r, c]) => { | |
| const row = startRow + r; | |
| const col = startCol + c; | |
| if (row >= 0 && row < rows && col >= 0 && col < cols) { | |
| grid[row][col] = 1; | |
| } | |
| }); | |
| drawGrid(); | |
| } | |
| function loadPattern(name) { | |
| pause(); | |
| const patterns = { | |
| glider: [[0,1],[1,2],[2,0],[2,1],[2,2]], | |
| spaceship: [[0,1],[0,4],[1,0],[2,0],[2,4],[3,0],[3,1],[3,2],[3,3]], | |
| pulsar: [ | |
| [0,2],[0,3],[0,4],[0,8],[0,9],[0,10], | |
| [2,0],[2,5],[2,7],[2,12], | |
| [3,0],[3,5],[3,7],[3,12], | |
| [4,0],[4,5],[4,7],[4,12], | |
| [5,2],[5,3],[5,4],[5,8],[5,9],[5,10], | |
| [7,2],[7,3],[7,4],[7,8],[7,9],[7,10], | |
| [8,0],[8,5],[8,7],[8,12], | |
| [9,0],[9,5],[9,7],[9,12], | |
| [10,0],[10,5],[10,7],[10,12], | |
| [12,2],[12,3],[12,4],[12,8],[12,9],[12,10] | |
| ], | |
| gosper: [ | |
| [5,1],[5,2],[6,1],[6,2], | |
| [3,13],[3,14],[4,12],[4,16],[5,11],[5,17],[6,11],[6,15],[6,17],[6,18],[7,11],[7,17],[8,12],[8,16],[9,13],[9,14], | |
| [1,25],[2,23],[2,25],[3,21],[3,22],[4,21],[4,22],[5,21],[5,22],[6,23],[6,25],[7,25], | |
| [3,35],[3,36],[4,35],[4,36] | |
| ] | |
| }; | |
| if (patterns[name]) { | |
| placePattern(patterns[name], 8, 12); | |
| } | |
| } | |
| drawGrid(); | |
| </script> | |
| </body> | |
| </html> | |