engine.js

At 65bd8a6

65bd8a6History

Preview

Code · 2.1 KiB
export const SIZE = 22;
export const DIRECTIONS = { up: { x: 0, y: -1 }, down: { x: 0, y: 1 }, left: { x: -1, y: 0 }, right: { x: 1, y: 0 } };
export const equal = (a, b) => a && b && a.x === b.x && a.y === b.y;
export const layouts = [[3,3],[10,3],[18,4],[6,6],[15,7],[3,11],[18,12],[8,14],[13,16],[4,18],[18,18],[11,20]];
export function spawnFood(state, random = Math.random) {
  const free = [];
  for(let y=0;y<SIZE;y++) for(let x=0;x<SIZE;x++) {
    const p={x,y};
    if(!state.snake.some(s=>equal(s,p)) && !state.obstacles.some(s=>equal(s,p))) free.push(p);
  }
  return free.length ? free[Math.min(free.length-1,Math.floor(random()*free.length))] : null;
}
export function createGame(types = ['ghost','pumpkin','candle'], random = Math.random) {
  const state = { snake:[{x:8,y:10},{x:7,y:10},{x:6,y:10},{x:5,y:10}], direction:'right', queue:[], score:0, status:'ready', obstacles:types.length ? layouts.map(([x,y],i)=>({x,y,type:types[i%types.length]})) : [] };
  state.food=spawnFood(state,random); return state;
}
export function turn(state, direction) {
  if(!DIRECTIONS[direction] || state.queue.length>=2 || state.status!=='playing') return;
  const last=state.queue.at(-1)||state.direction;
  const a=DIRECTIONS[last],b=DIRECTIONS[direction];
  if(a.x+b.x===0 && a.y+b.y===0 || last===direction) return;
  state.queue.push(direction);
}
export function tick(state,random=Math.random) {
  if(state.status!=='playing') return;
  state.direction=state.queue.shift()||state.direction;
  const d=DIRECTIONS[state.direction], h=state.snake[0], next={x:h.x+d.x,y:h.y+d.y};
  const eating=equal(next,state.food), body=eating?state.snake:state.snake.slice(0,-1);
  if(next.x<0||next.y<0||next.x>=SIZE||next.y>=SIZE||body.some(p=>equal(p,next))||state.obstacles.some(p=>equal(p,next))) {
    state.status='over'; return;
  }
  state.snake.unshift(next);
  if(eating) { state.score+=10; state.food=spawnFood(state,random); if(!state.food) state.status='won'; }
  else state.snake.pop();
}
export function interval(difficulty, score) { return Math.max(65, ({cozy:210,haunted:150,cursed:105}[difficulty]||150)-Math.floor(score/50)*7); }

Files