Snake · ling-2.6-flash
Build a playable Snake game on a canvas with arrow-key controls, a growing tail, food, score, and a game-over and restart state.
This one-shot run produced no runnable artifact.
agent produced no index.html
The transcript below shows what the model did — read it to see why the one shot fell short.
transcript · 2 messages
Build a playable Snake game on a canvas with arrow-key controls, a growing tail, food, score, and a game-over and restart state.
I'll create a complete Snake game in a single HTML file with all the requested features. ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Snake Game</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: #1a1a2e; font-family: 'Courier New', monospace; color: #eee; } #game-container { text-align: center; } #game-canvas { border: 2px solid #16213e; border-radius: 8px; background: #0f3460; } #score { font-size: 24px; margin: 10px 0; color: #e94560; } #message { font-size: 20px; margin: 10px 0; min-height: 28px; color: #e94560; } #restart-btn { display: none; padding: 10px 24px; font-size: 18px; font-family: 'Courier New', monospace; background: #e94560; color: white; border: none; border-radius: 6px; cursor: pointer; margin-top: 10px; } #restart-btn:hover { background: #bf365c; } #controls { font-size: 12px; color: #aaa; margin-top: 8px; } </style> </head> <body> <div id="game-container"> <canvas id="game-canvas" width="400" height="400"></canvas> <div id="score">Score: 0</div> <div id="message">Use Arrow Keys to Play</div> <button id="restart-btn">Play Again</button> <div id="controls">Arrow Keys / WASD to Control Snake</div> </div> <script> const canvas = document.getElementById('game-canvas'); const ctx = canvas.getContext('2d'); const scoreEl = document.getElementById('score'); const messageEl = document.getElementById('message'); const restartBtn = document.getElementById('restart-btn'); // Game constants const TILE_SIZE = 20; const GRID_SIZE = canvas.width / TILE_SIZE; // 20x20 grid // Game state let snake, food, score, gameRunning, gameOver, direction, nextDirection; // Initialize game function initGame() { snake = [{ x: 10, y: 10 }]; food = generateFood(); score = 0; gameRunning = true; gameOver = false; direction = 'right'; nextDirection = 'right'; scoreEl.textContent = 'Score: 0'; messageEl.textContent = 'Use Arrow Keys to Play'; restartBtn.style.display = 'none'; draw(); } // Generate food at a random position not on the snake function generateFood() { let newFood; do { newFood = { x: Math.floor(Math.random() * GRID_SIZE), y: Math.floor(Math.random() * GRID_SIZE) }; } while (snake.some(segment => segment.x === newFood.x && segment.y === newFood.y)); return newFood; } // Draw everything on the canvas function draw() { // Clear canvas ctx.fillStyle = '#0f3460'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw grid lines ctx.strokeStyle = 'rgba(255, 255, 255, 0.05)'; ctx.lineWidth = 1; for (let i = 0; i <= GRID_SIZE; i++) { ctx.beginPath(); ctx.moveTo(i * TILE_SIZE, 0); ctx.lineTo(i * TILE_SIZE, canvas.height); ctx.stroke(); ctx.beginPath(); ctx.moveTo(0, i * TILE_SIZE); ctx.lineTo(canvas.width, i * TILE_SIZE); ctx.stroke(); } // Draw food ctx.fillStyle = '#e94560'; ctx.beginPath(); const foodPadding = 2; ctx.roundRect( food.x * TILE_SIZE + foodPadding, food.y * TILE_SIZE + foodPadding, TILE_SIZE - foodPadding * 2, TILE_SIZE - foodPadding * 2, 3 ); ctx.fill(); // Draw snake snake.forEach((segment, index) => { if (index === 0) { // Snake head - darker gradient const headGrad = ctx.createLinearGradient( segment.x * TILE_SIZE, segment.y * TILE_SIZE, (segment.x + 1) * TILE_SIZE, (segment.y + 1) * TILE_SIZE ); headGrad.addColorStop(0, '#1783ff'); headGrad.addColorStop(1, '#003d7a'); ctx.fillStyle = headGrad; } else { // Snake body const bodyGrad = ctx.createLinearGradient( segment.x * TILE_SIZE, segment.y * TILE_SIZE, (segment.x + 1) * TILE_SIZE, (segment.y + 1) * TILE_SIZE ); bodyGrad.addColorStop(0, '#2a9d8f'); bodyGrad.addColorStop(1, '#1d6b5e); ctx.fillStyle = bodyGrad; } ctx.beginPath(); ctx.roundRect( segment.x * TILE_SIZE + 1, segment.y * TILE_SIZE + 1, TILE_SIZE - 2, TILE_SIZE - 2, 3 ); ctx.fill(); // Add subtle border to segments ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)'; ctx.lineWidth = 0.5; ctx.stroke(); }); // Draw game over overlay if (gameOver) { ctx.fillStyle = 'rgba(0, 0, 0, 0.6)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#e94560'; ctx.font = 'bold 32px "Courier New"'; ctx.textAlign = 'center'; ctx.fillText('GAME OVER', canvas.width / 2, canvas.height / 2 - 20); ctx.fillStyle = '#eee'; ctx.font = '16px "Courier New"'; ctx.fillText(`Final Score: ${score}`, canvas.width / 2, canvas.height / 2 + 20); ctx.textAlign = 'left'; } // Draw paused overlay if (!gameRunning && !gameOver) { ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#eee'; ctx.font = 'bold 24px "Courier New"'; ctx.textAlign = 'center'; ctx.fillText('PAUSED', canvas.width / 2, canvas.height / 2); ctx.textAlign = 'left'; } } // Change snake direction (prevents 180-degree turns) function changeDir(newDir) { if (!gameRunning) return; if (newDir === 'up' && direction !== 'down') nextDirection = 'up'; if (newDir === 'down' && direction !== 'up') nextDirection = 'down'; if (newDir === 'left' && direction !== 'right') nextDirection = 'left'; if (newDir === 'right' && direction !== 'left') nextDirection = 'right'; } // Check collision with walls or self function checkCollision(head) { // Wall collision if (head.x < 0 || head.x >= GRID_SIZE || head.y < 0 || head.y >= GRID_SIZE) { return true; } // Self collision (skip the head from checking against itself, and the immediate tail since it moves away) for (let i = 1; i < snake.length - 1; i++) { if (head.x === snake[i].x && head.y === snake[i].y) { return true; } } return false; } // Update game state function update() { if (!gameRunning || gameOver) return; direction = nextDirection; const head = { ...snake[0] }; // Move head switch (direction) { case 'up': head.y--; break; case 'down': head.y++; break; case 'left': head.x--; break; case 'right': head.x++; break; } // Check collision if (checkCollision(head)) { gameOver = true; gameRunning = false; messageEl.textContent = 'Game Over! Press Play Again'; restartBtn.style.display = 'inline-block'; draw(); return; } snake.unshift(head); // Check food collision if (head.x === food.x && head.y === food.y) { score += 10; scoreEl.textContent = `Score: ${score}`; food = generateFood(); // Speed increases slightly with score gameSpeed = Math.max(80, 150 - Math.floor(score / 5) * 5); } else { snake.pop(); } draw(); } // Main game loop let gameSpeed = 150; let gameLoop = null; function loop() { update(); if (!gameOver) { gameLoop = setTimeout(loop, gameSpeed); } } // Keyboard controls document.addEventListener('keydown', (e) => { switch (e.key) { case 'ArrowUp': changeDir('up'); break; case 'ArrowDown': changeDir('down'); break; case 'ArrowLeft': changeDir('left'); break; case 'ArrowRight': changeDir('right'); break; case 'KeyW': changeDir('up'); break; case 'KeyS': changeDir('down'); break; case 'KeyA': changeDir('left'); break; case 'KeyD': changeDir('right'); break; case ' ': e.preventDefault(); togglePause(); break; } }); // Pause/Resume function togglePause() { if (gameOver) return; gameRunning = !gameRunning; if (gameRunning) { messageEl.textContent = 'Use Arrow Keys to Play'; loop(); } else { clearTimeout(gameLoop); messageEl.textContent = 'Paused - Press Space or Click Play Again to Resume'; } draw(); } // Restart game function restart() { clearTimeout(gameLoop); initGame(); loop(); } restartBtn.addEventListener('click', restart); // Start the game initGame(); </script> </body> </html> ``` This Snake game includes: **Core Features:** - **Canvas-based gameplay** with a 400×400 grid (20×20 tiles) - **Arrow key controls** (plus WASD for alternative controls) - **Growing snake tail** - the snake grows by one segment each time it eats food - **Red food** that respawns at random valid positions - **Score tracking** - +10 points per food, with speed gradually increasing - **Game over detection** - collision with walls or self - **Restart button** - "Play Again" to reset the game **Additional Features:** - **Pause/Resume** with Space bar or clicking the restart button when paused - **Increasing difficulty** - snake speed increases as your score grows - **Visual design** - snake head with gradient, grid background, rounded food and segments - **Game states** - start screen, playing, game over overlay, and paused state - **Collision detection** - proper wall and self-collision with no 180° turning allowed
TAKE IT TO CODE
This run produced no artifact — reuse the prompt with a different model or your own pi-agent run.