```html Snake Game
Score: 0
``` ```typescript type Point = { x: number; y: number }; type Direction = 'UP' | 'DOWN' | 'LEFT' | 'RIGHT'; class SnakeGame { private canvas: HTMLCanvasElement; private ctx: CanvasRenderingContext2D; private scoreElement: HTMLElement; private readonly gridSize: number = 20; private readonly tileCount: number = 20; private snake: Point[] = [{ x: 10, y: 10 }]; private food: Point = { x: 5, y: 5 }; private dx: number = 0; private dy: number = 0; private nextDx: number = 0; private nextDy: number = 0; private score: number = 0; private isGameOver: boolean = false; constructor() { this.canvas = document.getElementById('gameCanvas') as HTMLCanvasElement; this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D; this.scoreElement = document.getElementById('score') as HTMLElement; window.addEventListener('keydown', (e) => this.handleKeyPress(e)); this.gameLoop(); } private handleKeyPress(e: KeyboardEvent): void { switch (e.key) { case 'ArrowUp': if (this.dy === 0) { this.nextDx = 0; this.nextDy = -1; } break; case 'ArrowDown': if (this.dy === 0) { this.nextDx = 0; this.nextDy = 1; } break; case 'ArrowLeft': if (this.dx === 0) { this.nextDx = -1; this.nextDy = 0; } break; case 'ArrowRight': if (this.dx === 0) { this.nextDx = 1; this.nextDy = 0; } break; } } private spawnFood(): void { this.food = { x: Math.floor(Math.random() * this.tileCount), y: Math.floor(Math.random() * this.tileCount) }; // Ensure food doesn't spawn inside snake body if (this.snake.some(segment => segment.x === this.food.x && segment.y === this.food.y)) { this.spawnFood(); } } private update(): void { if (this.isGameOver) return; this.dx = this.nextDx; this.dy = this.nextDy; if (this.dx === 0 && this.dy === 0) return; const head = { x: this.snake[0].x + this.dx, y: this.snake[0].y + this.dy }; // Wall Collision if (head.x < 0 || head.x >= this.tileCount || head.y < 0 || head.y >= this.tileCount) { this.isGameOver = true; return; } // Self Collision if (this.snake.some(segment => segment.x === head.x && segment.y === head.y)) { this.isGameOver = true; return; } this.snake.unshift(head); // Food Collision if (head.x === this.food.x && head.y === this.food.y) { this.score += 10; this.scoreElement.innerText = this.score.toString(); this.spawnFood(); } else { this.snake.pop(); } } private draw(): void { // Clear Canvas this.ctx.fillStyle = '#34495e'; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); // Draw Food this.ctx.fillStyle = '#e74c3c'; this.ctx.fillRect(this.food.x * this.gridSize, this.food.y * this.gridSize, this.gridSize - 2, this.gridSize - 2); // Draw Snake this.ctx.fillStyle = '#2ecc71'; this.snake.forEach(segment => { this.ctx.fillRect(segment.x * this.gridSize, segment.y * this.gridSize, this.gridSize - 2, this.gridSize - 2); }); if (this.isGameOver) { this.ctx.fillStyle = 'white'; this.ctx.font = '30px Arial'; this.ctx.textAlign = 'center'; this.ctx.fillText('GAME OVER', this.canvas.width / 2, this.canvas.height / 2); } } private gameLoop(): void { this.update(); this.draw(); setTimeout(() => this.gameLoop(), 100); } } new SnakeGame(); ```