import {GameOver} from "./Game.js"; export class Snake { /** * The snake of the game * @param options */ constructor({startPos = [8,8], size = 4, startDirection = directions.RIGHT} = {}) { if (startPos && Array.isArray(startPos) && startPos.length === 2 && startPos.filter(s => typeof s === "number" && s > 0 && s % 1 === 0).length === startPos.length) this.body = [startPos]; else throw new InvalidSnakeOption("startPos"); if (size && typeof size === "number" && size > 1 && size % 1 === 0) this.size = size; else throw new InvalidSnakeOption("size"); // Generate snake body for (let s = 1; s < this.size; s++) { const pos = this.body[this.body.length - 1].map((n, i) => n - startDirection[i]); if (pos.find(v => v < 0)) throw new InvalidSnakeOption("startPos too small"); this.body.push(pos); } this.eating = false; this.narrowing = false; } /** * Move the snake body * @param {directions} direction */ move(direction) { if (!this.eating) this.body.pop(); else this.eating = false; const pos = this.body[0].map((n, i) => n + direction[i]); if (this.body.find(([x,y]) => pos[0] === x && pos[1] === y)) throw new GameOver(); if (!this.narrowing) this.body.unshift(pos); else this.narrowing = false; } /** * Enable eating */ eat() { this.eating = true; } /** * Enable narrowing */ shrink() { this.narrowing = true; } } export const directions = { UP: [0, -1], RIGHT: [1, 0], DOWN: [0, 1], LEFT: [-1, 0] }; export class InvalidSnakeOption extends Error { /** * @param {string} name */ constructor(name) { super(`Invalid Snake option: ${name}`); } }