Monday, January 12, 2026

Snake Game AI Coding Test

Snake Game

Use arrow keys to control the snake. Eat the red food to grow and earn points. Avoid walls and yourself!
Score: 0
High Score: 0
Game Over!
Use Arrow Keys (↑, ↓, ←, →) to control direction

Source Code

<div class="snake-game-wrapper">
  <style>
    .snake-game-wrapper {
      max-width: 600px;
      margin: 0 auto;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
      text-align: center;
      color: #333;
    }
    
    .game-header {
      margin-bottom: 15px;
    }
    
    .instructions {
      background: #f8f9fa;
      padding: 12px;
      border-radius: 8px;
      margin-bottom: 15px;
      font-size: 14px;
      color: #666;
      border: 1px solid #e9ecef;
    }
    
    .score-container {
      display: flex;
      justify-content: center;
      gap: 30px;
      margin-bottom: 15px;
      font-weight: bold;
      font-size: 18px;
    }
    
    .current-score {
      color: #4CAF50;
    }
    
    .high-score {
      color: #2196F3;
    }
    
    .game-container {
      position: relative;
      margin-bottom: 20px;
    }
    
    .game-canvas {
      background-color: #1a1a1a;
      border-radius: 8px;
      border: 2px solid #333;
      display: block;
      margin: 0 auto;
    }
    
    .game-button {
      background: #4CAF50;
      color: white;
      border: none;
      padding: 12px 30px;
      font-size: 16px;
      font-weight: bold;
      border-radius: 6px;
      cursor: pointer;
      transition: all 0.2s;
      box-shadow: 0 4px 6px rgba(0,0,0,0.1);
    }
    
    .game-button:hover {
      background: #45a049;
      transform: translateY(-2px);
      box-shadow: 0 6px 8px rgba(0,0,0,0.15);
    }
    
    .game-button:active {
      transform: translateY(0);
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
    
    .game-over {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background: rgba(0, 0, 0, 0.85);
      color: white;
      padding: 20px 30px;
      border-radius: 8px;
      font-size: 24px;
      font-weight: bold;
      display: none;
      box-shadow: 0 8px 16px rgba(0,0,0,0.3);
    }
    
    .controls-info {
      font-size: 13px;
      color: #777;
      margin-top: 15px;
    }
  </style>

  <div class="game-header">
    <h2>Snake Game</h2>
    <div class="instructions">
      Use arrow keys to control the snake. Eat the red food to grow and earn points. Avoid walls and yourself!
    </div>
  </div>
  
  <div class="score-container">
    <div class="current-score">Score: <span id="currentScore">0</span></div>
    <div class="high-score">High Score: <span id="highScore">0</span></div>
  </div>
  
  <div class="game-container">
    <canvas class="game-canvas" width="400" height="400"></canvas>
    <div class="game-over" id="gameOverText">Game Over!</div>
  </div>
  
  <button class="game-button" id="startButton">Start Game</button>
  <div class="controls-info">Use Arrow Keys (↑, ↓, ←, →) to control direction</div>

  <script>
    // Game state and configuration
    const gameState = {
      canvas: null,
      ctx: null,
      snake: [],
      food: { x: 0, y: 0 },
      direction: { x: 1, y: 0 },
      nextDirection: { x: 1, y: 0 },
      gridSize: 20,
      gameLoopId: null,
      score: 0,
      highScore: 0,
      isRunning: false,
      speed: 100 // milliseconds per move
    };

    // Initialize game
    function initGame() {
      gameState.canvas = document.querySelector('.game-canvas');
      gameState.ctx = gameState.canvas.getContext('2d');
      
      // Load high score from localStorage
      gameState.highScore = parseInt(localStorage.getItem('snakeHighScore')) || 0;
      document.getElementById('highScore').textContent = gameState.highScore;
      
      // Set up event listeners
      document.addEventListener('keydown', handleKeyPress);
      document.getElementById('startButton').addEventListener('click', startGame);
      
      // Draw initial static state
      drawStatic();
    }

    // Draw static elements (border, initial text)
    function drawStatic() {
      gameState.ctx.fillStyle = '#1a1a1a';
      gameState.ctx.fillRect(0, 0, gameState.canvas.width, gameState.canvas.height);
      
      // Draw grid pattern (subtle)
      gameState.ctx.strokeStyle = '#222';
      gameState.ctx.lineWidth = 0.5;
      for (let x = 0; x <= gameState.canvas.width; x += gameState.gridSize) {
        gameState.ctx.beginPath();
        gameState.ctx.moveTo(x, 0);
        gameState.ctx.lineTo(x, gameState.canvas.height);
        gameState.ctx.stroke();
      }
      for (let y = 0; y <= gameState.canvas.height; y += gameState.gridSize) {
        gameState.ctx.beginPath();
        gameState.ctx.moveTo(0, y);
        gameState.ctx.lineTo(gameState.canvas.width, y);
        gameState.ctx.stroke();
      }
      
      // Initial instruction text
      gameState.ctx.fillStyle = '#666';
      gameState.ctx.font = '16px Arial';
      gameState.ctx.textAlign = 'center';
      gameState.ctx.fillText('Click "Start Game" to begin', 
                            gameState.canvas.width/2, 
                            gameState.canvas.height/2);
    }

    // Start or restart the game
    function startGame() {
      if (gameState.isRunning) {
        clearInterval(gameState.gameLoopId);
      }
      
      // Reset game state
      gameState.snake = [
        { x: 10, y: 10 },
        { x: 9, y: 10 },
        { x: 8, y: 10 }
      ];
      gameState.direction = { x: 1, y: 0 };
      gameState.nextDirection = { x: 1, y: 0 };
      gameState.score = 0;
      gameState.isRunning = true;
      
      // Update UI
      document.getElementById('currentScore').textContent = '0';
      document.getElementById('gameOverText').style.display = 'none';
      document.getElementById('startButton').textContent = 'Restart Game';
      
      // Generate initial food
      generateFood();
      
      // Start game loop
      gameState.gameLoopId = setInterval(gameLoop, gameState.speed);
      
      // Draw initial frame
      draw();
    }

    // Main game loop
    function gameLoop() {
      // Update direction from queued input
      gameState.direction = { ...gameState.nextDirection };
      
      // Calculate new head position
      const head = { ...gameState.snake[0] };
      head.x += gameState.direction.x;
      head.y += gameState.direction.y;
      
      // Check for collisions
      if (isCollision(head)) {
        gameOver();
        return;
      }
      
      // Add new head
      gameState.snake.unshift(head);
      
      // Check if food is eaten
      if (head.x === gameState.food.x && head.y === gameState.food.y) {
        // Increase score
        gameState.score += 10;
        document.getElementById('currentScore').textContent = gameState.score;
        
        // Update high score if needed
        if (gameState.score > gameState.highScore) {
          gameState.highScore = gameState.score;
          document.getElementById('highScore').textContent = gameState.highScore;
          localStorage.setItem('snakeHighScore', gameState.highScore.toString());
        }
        
        // Generate new food
        generateFood();
      } else {
        // Remove tail if no food eaten
        gameState.snake.pop();
      }
      
      // Draw updated game state
      draw();
    }

    // Check for collisions
    function isCollision(head) {
      // Wall collision
      if (head.x < 0 || head.x >= gameState.canvas.width / gameState.gridSize ||
          head.y < 0 || head.y >= gameState.canvas.height / gameState.gridSize) {
        return true;
      }
      
      // Self collision (skip head itself)
      for (let i = 1; i < gameState.snake.length; i++) {
        if (gameState.snake[i].x === head.x && gameState.snake[i].y === head.y) {
          return true;
        }
      }
      
      return false;
    }

    // Generate food at random location (not on snake)
    function generateFood() {
      let newFood;
      let foodOnSnake;
      
      do {
        foodOnSnake = false;
        newFood = {
          x: Math.floor(Math.random() * (gameState.canvas.width / gameState.gridSize)),
          y: Math.floor(Math.random() * (gameState.canvas.height / gameState.gridSize))
        };
        
        // Check if food would spawn on snake
        for (const segment of gameState.snake) {
          if (segment.x === newFood.x && segment.y === newFood.y) {
            foodOnSnake = true;
            break;
          }
        }
      } while (foodOnSnake);
      
      gameState.food = newFood;
    }

    // Draw everything on canvas
    function draw() {
      // Clear canvas
      gameState.ctx.fillStyle = '#1a1a1a';
      gameState.ctx.fillRect(0, 0, gameState.canvas.width, gameState.canvas.height);
      
      // Draw grid (subtle)
      gameState.ctx.strokeStyle = '#222';
      gameState.ctx.lineWidth = 0.5;
      for (let x = 0; x <= gameState.canvas.width; x += gameState.gridSize) {
        gameState.ctx.beginPath();
        gameState.ctx.moveTo(x, 0);
        gameState.ctx.lineTo(x, gameState.canvas.height);
        gameState.ctx.stroke();
      }
      for (let y = 0; y <= gameState.canvas.height; y += gameState.gridSize) {
        gameState.ctx.beginPath();
        gameState.ctx.moveTo(0, y);
        gameState.ctx.lineTo(gameState.canvas.width, y);
        gameState.ctx.stroke();
      }
      
      // Draw snake
      gameState.snake.forEach((segment, index) => {
        const x = segment.x * gameState.gridSize;
        const y = segment.y * gameState.gridSize;
        
        // Head is slightly brighter
        if (index === 0) {
          gameState.ctx.fillStyle = '#66BB6A';
        } else {
          gameState.ctx.fillStyle = '#4CAF50';
        }
        
        // Draw rounded segments
        gameState.ctx.beginPath();
        gameState.ctx.roundRect(x, y, gameState.gridSize, gameState.gridSize, 4);
        gameState.ctx.fill();
        
        // Add subtle border
        gameState.ctx.strokeStyle = '#388E3C';
        gameState.ctx.lineWidth = 1;
        gameState.ctx.stroke();
      });
      
      // Draw food
      const foodX = gameState.food.x * gameState.gridSize;
      const foodY = gameState.food.y * gameState.gridSize;
      
      gameState.ctx.fillStyle = '#f44336';
      gameState.ctx.beginPath();
      gameState.ctx.arc(foodX + gameState.gridSize/2, 
                       foodY + gameState.gridSize/2, 
                       gameState.gridSize/2 - 1, 0, Math.PI * 2);
      gameState.ctx.fill();
      
      // Add shine effect to food
      gameState.ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
      gameState.ctx.beginPath();
      gameState.ctx.arc(foodX + gameState.gridSize/2 - 3, 
                       foodY + gameState.gridSize/2 - 3, 
                       gameState.gridSize/6, 0, Math.PI * 2);
      gameState.ctx.fill();
    }

    // Handle keyboard input
    function handleKeyPress(event) {
      if (!gameState.isRunning) return;
      
      // Prevent default behavior for arrow keys to avoid page scrolling
      if ([37, 38, 39, 40].includes(event.keyCode)) {
        event.preventDefault();
      }
      
      let newDirection = { ...gameState.nextDirection };
      
      // Update direction based on key press, prevent opposite direction
      switch (event.keyCode) {
        case 37: // Left arrow
          if (gameState.direction.x !== 1) newDirection = { x: -1, y: 0 };
          break;
        case 38: // Up arrow
          if (gameState.direction.y !== 1) newDirection = { x: 0, y: -1 };
          break;
        case 39: // Right arrow
          if (gameState.direction.x !== -1) newDirection = { x: 1, y: 0 };
          break;
        case 40: // Down arrow
          if (gameState.direction.y !== -1) newDirection = { x: 0, y: 1 };
          break;
      }
      
      // Only update if direction actually changed
      if (newDirection.x !== gameState.nextDirection.x || 
          newDirection.y !== gameState.nextDirection.y) {
        gameState.nextDirection = newDirection;
      }
    }

    // Handle game over
    function gameOver() {
      gameState.isRunning = false;
      clearInterval(gameState.gameLoopId);
      
      // Show game over text
      const gameOverElement = document.getElementById('gameOverText');
      gameOverElement.textContent = `Game Over! Score: ${gameState.score}`;
      gameOverElement.style.display = 'block';
    }

    // Initialize game when page loads
    window.addEventListener('DOMContentLoaded', initGame);
  </script>
</div>
</div>

Source Prompt (Used on DeepSeek

Create a fully functional Snake game as a SINGLE DIV suitable for embedding in a Blogger post. Critical requirements:

STRUCTURE:
- Start with <div class="snake-game-wrapper"> and end with </div>
- NO <!DOCTYPE>, <html>, <head>, or <body> tags
- Include <style> tag inside the div with scoped CSS
- Include <script> tag inside the div
- All code must be self-contained with no external dependencies

FUNCTIONALITY:
- Canvas-based Snake game (400x400px recommended)
- Arrow keys control direction (prevent opposite-direction moves)
- Snake starts at center, length 3, moving right automatically on game start
- Food spawns randomly (never on snake body)
- Snake grows one segment per food eaten
- Score increments with each food
- High score persists using localStorage
- Game over on wall collision or self-collision
- Clear "Start Game" button to begin/restart
- Display current score and high score

GAMEPLAY REQUIREMENTS:
- Game must start moving immediately when Start is clicked (don't wait for arrow key)
- Movement must be smooth and continuous at ~100ms intervals
- Direction changes must queue properly (no skipped inputs)
- Game loop must stop cleanly on game over

STYLE:
- Container max-width: 600px, centered
- Dark canvas background (#1a1a1a)
- Green snake (#4CAF50), red food (#f44336)
- Clean, modern UI with good contrast
- Brief instructions above canvas
- Professional button styling

CODE QUALITY:
- Clear comments explaining game logic
- Defensive coding (check boundaries, prevent bugs)
- Use const/let appropriately
- Test that the game actually works before returning

The game must be playable immediately when embedded - no debugging required.

No comments:

Get Real

Copy 🖨️ Print / Save as PDF Let's Get Real I gave Deep...