Home Notes Quotes

🐍 How I Built a Snake AI Showdown

By Katzir • June 22, 2025

Hey there! If you’re a PM like me—fascinated by game AI but intimidated by all the math-y jargon—this is for you. A few weekends ago I thought, “What if I built a Snake game that plays itself?” Seven snakes, each with its own brain: Random, Greedy, Tail-Aware, Loop-Safe, Lookahead, Expectimax, and MCTS. The result? The most fun I’ve ever had with vanilla JavaScript.

This post is half tutorial, half war story. We’ll explore how each AI works—why it makes its moves, not just what it does—and I’ll sprinkle in debugging anecdotes so you can laugh (or cry) along. Ready?

Try the live demo first →
Check it out on GitHub →

🤖 Demystifying Game AI

Game AI isn’t magic—it’s code that answers one question:

“Where should the snake move next?”

Each brain implements a different decision rule, from chaos to clever planning.

🎮 Seven AIs, One Arena

All in pure HTML/CSS/JS—no frameworks required.

📦 Project Structure

snake-ai-showdown/
├── index.html
├── game.html
├── style.css
├── snake.js
└── README.md

Each AI gets its own <canvas> and a fresh copy of the Snake logic.

🧠 AI Deep Dive: Theory & Code

1. 🟥 Random AI

Theory: No planning. Every tick, pick one of the legal neighbors at random.

function chooseRandom() {
  const moves = getValidMoves(head);
  return moves[Math.floor(Math.random() * moves.length)];
}

Anecdote: It often dies on the very first move—hilarity ensues.

2. 🟧 Greedy AI (A*)

Theory: A* searches for the shortest grid path to the apple using f(n)=g(n)+h(n), with Manhattan h.

function chooseGreedy() {
  const path = aStar(head, apple);
  return path ? path[1] : null;
}

Fast—but blind; it often crashes into its own tail.

3. 🟨 Tail-Aware AI

Theory: “If I take that apple, can I still reach my tail afterward?”

function chooseTailAware() {
  const pA = aStar(head, apple);
  if (pA && isPathSafe(pA)) return pA[1];
  const pT = aStar(head, tail);
  return pT ? pT[1] : chooseRandom();
}

isPathSafe(path) simulates growing along path then checks head→tail reachability.

4. 🟩 Loop-Safe AI

Theory: Tail-Aware plus loop detection & auto-restart:

  1. Try apple if safe
  2. Else chase tail
  3. Else random
  4. If stuck (>200 ticks & <10 unique heads), restart()
function chooseLoopSafe() {
  if (isSafe(pathToApple)) return pathToApple[1];
  if (pathToTail) return pathToTail[1];
  if (isStuckInLoop()) { restart(); return; }
  return chooseRandom();
}

5. 🔵 Lookahead AI

Theory: Minimax to depth 3. Simulate moves, score each state by distance, free space, length.

function chooseLookahead(depth=3) {
  let best, bestScore = -Infinity;
  for (let mv of getValidMoves(head)) {
    const state = simulateState(snake, apple, mv);
    const score = minimax(state, depth-1);
    if (score > bestScore) { bestScore = score; best = mv; }
  }
  return best;
}

6. 🟣 Expectimax AI

Theory: Like lookahead, but treat apple‐spawn as a chance node—average over spawns.

function chooseExpectimax(depth=2) {
  // maximize over moves, then average over random apple positions
}

7. ⚫ MCTS AI

Theory: For each move, run 15 random rollouts (max 30 steps), pick highest average survival.

function chooseMCTS(sims=15, maxSteps=30) {
  // for each move: simulateRandomPlay, return argmax
}

🔧 Key Functions Explained

🎨 Styling & Layout

.tabs { display:flex; }
.pane { position:absolute; }
canvas { aspect-ratio:1/1; }

🚀 Deploy on GitHub Pages

git init
git add .
git commit -m "Snake AI Showdown"
git remote add origin https://github.com/yourusername/snake-ai-showdown.git
git push -u origin main

Then GitHub → Settings → Pages → main / root. Live at yourusername.github.io/snake-ai-showdown.

🧪 Lessons Learned

🔮 Next Up: Genetic Algorithms & Beyond

Seed your snakes with DNA and watch evolution unfold in your browser.
← Back to all posts

Let's Conjure Something Epic

I'm always on the lookout for new quests—collaborate, chat, or challenge me to build the next VR dragon simulator!