03 Coil

Grow a glowing tail while the arena closes in with every bite. Golden keys push the walls back out.

Controls Arrows or WASD to turn; on touch, tap the side of the head you want to turn toward

979 / 1024 bytes · 45 to spare

The 979 bytes that ship
for(_='],Ge[FF0]Eif(D"#&&t=)}33]|l/e.keydown=Fl]c.fillText(),,1;elseMath.f())=>{0,(F2]-E)e9e7df"*(F3]-F1])	=32*e.offsetlet ",Rect()|l.includes(/a.clientWidth-Style=localStorage.coil1k=l[l.length-e,l,t,f,i,n,o=random,d=sign,s=[328Gh=y=2,S=+||g=l=>l%<E|l%>=F2<F1>=F3Gk=(do{f=594*o()|0}while(g(ff),T=(e=[...sGl=[310G1,i=n=y=k(;T(y=2,n=99,onkeyonpointere=>{f,i1Go="awds".indexO;if=[-1,-,][~o?o:Code-37]{lXi%,tY(i/|0);f=l*l>t*t?d(l):*d(ty?n>40T():f||t},setInterval((Dn++,n%(11-min(i/5,5)|0)<11!=y){o1];o+2](-t);T=o+t;Dg(TT))y?-t:(y=1,n=i>S(=S=i)) Dl.push(TT!=f||y)l.shift(){i++,h=6;l=i%4,;+=d((i%5?[16,96,9]:s)[l]-g(T)|	<99(=tk(}h-- >0?:2a2a36321800b0b1010*E0*F1]0*0	[f,...l].map((e,ll?7cff6b":(i+1)%5?ff4f6d":ffd23fe%*110*(e/|09,9,y"COIL · TAP TO START"664i+"  HI "+S6206)';G=/[-D-G]/.exec(_);)with(_.split(G))_=join(shift());eval(_)
Readable source
// COIL: eat to grow; each bite closes a wall in, every 5th (gold) key pushes one out.
// Harness gives: a = 320x180 canvas, b = body, c = 2d context.
// Cells are ints n = y*33 + x (33 wide so the left/right edges never wrap).
// Walls L = [left, top, right, bottom], right/bottom exclusive. Direction q = cell delta.
let R = Math.random, sg = Math.sign, F = [0, 0, 32, 18];
let L, s, q, f, sc, t, fl = 0, dead = 2, best = +localStorage.coil1k || 0;

let out = n => n % 33 < L[0] | n % 33 >= L[2] | n / 33 < L[1] | n / 33 >= L[3];
// food: random cell, retried until it is inside the walls and off the tail
let spawn = () => { do f = R() * 594 | 0; while (out(f) | s.includes(f)); };
let start = () => { L = [...F]; s = [310]; q = 1; sc = t = dead = 0; spawn(); };
start(); dead = 2; t = 99;

onkeydown = onpointerdown = e => {
  let h = s[s.length - 1], i = 'awds'.indexOf(e.key), v;
  // key -> cell delta, else tap relative to the head
  if (e.key) v = [-1, -33, 1, 33][~i ? i : e.keyCode - 37];
  else {
    let x = e.offsetX * 32 / a.clientWidth - h % 33, y = e.offsetY * 32 / a.clientWidth - (h / 33 | 0);
    v = x * x > y * y ? sg(x) : sg(y) * 33;
  }
  if (dead) { if (t > 40) start(); }
  else q = v || q;
};

setInterval(() => {
  t++;
  // gentle ramp: frames per step 11 -> 6
  if (t % (11 - Math.min(sc / 5, 5) | 0) < 1 && dead != 1) {
    // a turn straight back into the neck is ignored (keeps going), so quick double-turns are safe
    let h = s[s.length - 1];
    if (h + q == s[s.length - 2]) q = -q;
    let n = h + q;
    if (out(n) | s.includes(n)) {
      // title demo bounces back; a real run dies
      if (dead) q = -q;
      else dead = 1, t = 0, sc > best && (localStorage.coil1k = best = sc);
    } else {
      s.push(n);
      if (n == f && !dead) {
        sc++; fl = 6;
        // bite: every 5th (key) the wall steps out, else it steps in (sides cycle)
        let i = sc % 4, o = L[i];
        L[i] += sg((sc % 5 ? [16, 9, 16, 9] : F)[i] - L[i]);
        // undo if it would crush the head or leave no room
        if (out(n) | (L[2] - L[0]) * (L[3] - L[1]) < 99) L[i] = o;
        spawn();
      } else s.shift();
    }
  }
  // walls are the dim zone (they flash on a bite), the arena is the floor
  c.fillStyle = fl-- > 0 ? '#e9e7df' : '#2a2a36';
  c.fillRect(0, 0, 320, 180);
  c.fillStyle = '#0b0b10';
  c.fillRect(L[0] * 10, L[1] * 10, (L[2] - L[0]) * 10, (L[3] - L[1]) * 10);
  // food (gold when it is the key), then tail
  [f, ...s].map((p, i) => {
    c.fillStyle = i ? '#7cff6b' : (sc + 1) % 5 ? '#ff4f6d' : '#ffd23f';
    c.fillRect(p % 33 * 10, (p / 33 | 0) * 10, 9, 9);
  });
  c.fillStyle = '#e9e7df';
  if (dead) c.fillText('COIL · TAP TO START', 160, 64);
  c.fillText(sc + '  HI ' + best, 160, 20);
}, 16);