---
---
<canvas id="snake-canvas" class="rounded-lg" style="
  padding: 2px;
  border: 2px solid transparent;
  background-image: linear-gradient(var(--ctp-base), var(--ctp-base)), linear-gradient(to right, var(--ctp-red), var(--ctp-peach), var(--ctp-yellow), var(--ctp-green), var(--ctp-teal), var(--ctp-blue), var(--ctp-mauve));
  background-origin: border-box;
  background-clip: padding-box, border-box;
"></canvas>

<script>
  const canvas = document.getElementById('snake-canvas') as HTMLCanvasElement;
const size = 15;
const cols = 27;
const gameRows = 26;
const uiHeight = 30;
canvas.width = cols * size;
canvas.height = gameRows * size + uiHeight;
  const ctx = canvas.getContext('2d')!;
  const rows = gameRows;

  let snake: {x: number, y: number}[] = [];
  let dir = { x: 1, y: 0 };
  let food = { x: 0, y: 0 };
  let running = false;
  let aiMode = false;
  let aiPath: {x: number, y: number}[] = [];
  let interval: ReturnType<typeof setInterval> | null = null;

  function getColor(v: string) {
    return getComputedStyle(document.documentElement).getPropertyValue(v).trim();
  }

  function randomFood() {
    let f;
    do { f = { x: Math.floor(Math.random() * cols), y: Math.floor(Math.random() * rows) }; }
    while (snake.some(s => s.x === f.x && s.y === f.y));
    return f;
  }

  function astar(start: {x:number,y:number}, goal: {x:number,y:number}, blocked: Set<string>) {
    const key = (p: {x:number,y:number}) => `${p.x},${p.y}`;
    const h = (p: {x:number,y:number}) => Math.abs(p.x - goal.x) + Math.abs(p.y - goal.y);
    const open = [{ pos: start, g: 0, f: h(start), path: [] as {x:number,y:number}[] }];
    const visited = new Set<string>();
    while (open.length) {
      open.sort((a, b) => a.f - b.f);
      const current = open.shift()!;
      const k = key(current.pos);
      if (visited.has(k)) continue;
      visited.add(k);
      if (current.pos.x === goal.x && current.pos.y === goal.y) return current.path;
      for (const d of [{x:1,y:0},{x:-1,y:0},{x:0,y:1},{x:0,y:-1}]) {
        const next = { x: current.pos.x + d.x, y: current.pos.y + d.y };
        if (next.x < 0 || next.x >= cols || next.y < 0 || next.y >= rows) continue;
        if (blocked.has(key(next))) continue;
        if (visited.has(key(next))) continue;
        const g = current.g + 1;
        open.push({ pos: next, g, f: g + h(next), path: [...current.path, next] });
      }
    }
    return null;
  }

  function aiStep() {
    const blocked = new Set(snake.slice(0, -1).map(s => `${s.x},${s.y}`));
    const path = astar(snake[0], food, blocked);
    if (path && path.length > 0) {
      aiPath = path;
      const next = path[0];
      dir = { x: next.x - snake[0].x, y: next.y - snake[0].y };
    } else {
      aiPath = [];
      const options = [{x:1,y:0},{x:-1,y:0},{x:0,y:1},{x:0,y:-1}];
      for (const d of options) {
        const next = { x: snake[0].x + d.x, y: snake[0].y + d.y };
        if (next.x >= 0 && next.x < cols && next.y >= 0 && next.y < rows && !blocked.has(`${next.x},${next.y}`)) {
          dir = d;
          break;
        }
      }
    }
  }

  function drawGrid() {
    ctx.strokeStyle = getColor('--ctp-surface');
    ctx.lineWidth = 0.5;
    for (let x = 0; x <= canvas.width; x += size) {
      ctx.beginPath(); ctx.moveTo(x, uiHeight); ctx.lineTo(x, canvas.height); ctx.stroke();
    }
    for (let y = uiHeight; y <= canvas.height; y += size) {
      ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(canvas.width, y); ctx.stroke();
    }
  }

  function drawUI() {
    const btnW = 80;
		const btnH = 20;
		const btnY = (uiHeight - btnH) / 2;
		const totalW = btnW * 2 + 10;
		const startX = (canvas.width - totalW) / 2;

		// Manual button
		ctx.fillStyle = !aiMode ? getColor('--ctp-accent') : getColor('--ctp-surface');
		ctx.beginPath();
		ctx.roundRect(startX, btnY, btnW, btnH, 4);
		ctx.fill();
		ctx.fillStyle = !aiMode ? getColor('--ctp-base') : getColor('--ctp-subtext');
		ctx.font = '12px monospace';
		ctx.textAlign = 'center';
		ctx.textBaseline = 'middle';
		ctx.fillText('Manual', startX + btnW / 2, uiHeight / 2);

		// AI button
		const aiX = startX + btnW + 10;
		ctx.fillStyle = aiMode ? getColor('--ctp-accent') : getColor('--ctp-surface');
		ctx.beginPath();
		ctx.roundRect(aiX, btnY, btnW, btnH, 4);
		ctx.fill();
		ctx.fillStyle = aiMode ? getColor('--ctp-base') : getColor('--ctp-subtext');
		ctx.fillText('AI', aiX + btnW / 2, uiHeight / 2);
  }

  function draw() {
    ctx.fillStyle = getColor('--ctp-base');
    ctx.fillRect(0, uiHeight, canvas.width, canvas.height - uiHeight);
    drawGrid();
    drawUI();

    // draw AI path
    if (aiMode && aiPath.length > 0) {
      ctx.fillStyle = `color-mix(in srgb, ${getColor('--ctp-teal')} 25%, transparent)`;
      aiPath.forEach(p => {
        ctx.fillRect(p.x * size, uiHeight + p.y * size, size - 1, size - 1);
      });
    }

    ctx.fillStyle = getColor('--ctp-accent');
    snake.forEach(s => ctx.fillRect(s.x * size, uiHeight + s.y * size, size - 1, size - 1));

    ctx.fillStyle = getColor('--ctp-red');
    ctx.fillRect(food.x * size, uiHeight + food.y * size, size - 1, size - 1);
  }

  function drawWaiting() {
    ctx.fillStyle = getColor('--ctp-base');
    ctx.fillRect(0, uiHeight, canvas.width, canvas.height - uiHeight);
    drawGrid();
    drawUI();
    ctx.fillStyle = getColor('--ctp-subtext');
    ctx.font = '14px monospace';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
		  ctx.fillText('Press SPACE to start', canvas.width / 2, uiHeight + (canvas.height - uiHeight) / 2);
  }

  function drawGameOver() {
    ctx.fillStyle = getColor('--ctp-base');
    ctx.fillRect(0, uiHeight, canvas.width, canvas.height - uiHeight);
    drawGrid();
    drawUI();
    ctx.fillStyle = getColor('--ctp-text');
    ctx.font = '20px monospace';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText('Game Over', canvas.width / 2, uiHeight + (canvas.height - uiHeight) / 2 - 16);
    if (!aiMode) {
      ctx.font = '14px monospace';
      ctx.fillStyle = getColor('--ctp-subtext');
      ctx.fillText('Press SPACE to restart', canvas.width / 2, uiHeight + (canvas.height - uiHeight) / 2 + 16);
    }
  }

  function init() {
    snake = [{ x: Math.floor(cols / 2), y: Math.floor(rows / 2) }];
    dir = { x: 1, y: 0 };
    food = randomFood();
    aiPath = [];
    running = true;
    if (interval) clearInterval(interval);
    interval = setInterval(tick, aiMode ? 50 : 120);
    draw();
  }

  function tick() {
    if (aiMode) aiStep();
    const head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };
    if (head.x < 0 || head.x >= cols || head.y < 0 || head.y >= rows || snake.some(s => s.x === head.x && s.y === head.y)) {
      running = false;
      if (interval) clearInterval(interval);
      drawGameOver();
      if (aiMode) setTimeout(init, 800);
      return;
    }
    snake.unshift(head);
    if (head.x === food.x && head.y === food.y) {
      food = randomFood();
    } else {
      snake.pop();
    }
    draw();
  }

  function setMode(ai: boolean) {
    aiMode = ai;
    if (interval) clearInterval(interval);
    running = false;
    aiPath = [];
    if (ai) {
      init();
    } else {
      drawWaiting();
    }
  }

  canvas.addEventListener('click', (e) => {
  const rect = canvas.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
  const totalW = 80 * 2 + 10;
  const startX = (canvas.width - totalW) / 2;
  if (y < uiHeight) {
    if (x >= startX && x <= startX + 80) setMode(false);
    if (x >= startX + 90 && x <= startX + 170) setMode(true);
  }
});

  document.addEventListener('keydown', (e) => {
    if (e.key === ' ') {
      e.preventDefault();
      if (!aiMode && !running) init();
      return;
    }
    if (aiMode) return;
    if (e.key === 'ArrowUp' && dir.y === 0) dir = { x: 0, y: -1 };
    if (e.key === 'ArrowDown' && dir.y === 0) dir = { x: 0, y: 1 };
    if (e.key === 'ArrowLeft' && dir.x === 0) dir = { x: -1, y: 0 };
    if (e.key === 'ArrowRight' && dir.x === 0) dir = { x: 1, y: 0 };
  });

  requestAnimationFrame(() => drawWaiting());

</script>
