/* helper – robust coord access */ function cx(c) { return (c.x !== undefined) ? c.x : c[0]; } function cy(c) { return (c.y !== undefined) ? c.y : c[1]; } /* simple move-shape checks */ var deltas = { pawn: function (pc, dx, dy, grid, to) { var dir = (pc.colour === 'white') ? -1 : 1; var base = (pc.colour === 'white') ? 6 : 1; var one = (dy === dir && dx === 0 && grid.at(to).length === 0); var two = (dy === 2 * dir && dx === 0 && cy(pc.coord) === base && grid.at({ x: cx(pc.coord), y: cy(pc.coord)+dir }).length === 0 && grid.at(to).length === 0); var cap = (dy === dir && Math.abs(dx) === 1 && grid.at(to).length); return one || two || cap; }, rook : function (pc, dx, dy) { return (dx === 0 || dy === 0); }, bishop: function (pc, dx, dy) { return Math.abs(dx) === Math.abs(dy); }, queen : function (pc, dx, dy) { return (dx === 0 || dy === 0 || Math.abs(dx) === Math.abs(dy)); }, knight: function (pc, dx, dy) { return (Math.abs(dx) === 1 && Math.abs(dy) === 2) || (Math.abs(dx) === 2 && Math.abs(dy) === 1); }, king : function (pc, dx, dy) { return Math.max(Math.abs(dx), Math.abs(dy)) === 1; } }; function clearLine(from, to, grid) { var dx = Math.sign(cx(to) - cx(from)); var dy = Math.sign(cy(to) - cy(from)); var x = cx(from) + dx, y = cy(from) + dy; while (x !== cx(to) || y !== cy(to)) { if (grid.at({ x: x, y: y }).length) return false; x += dx; y += dy; } return true; } function canMove(piece, from, to, grid) { var dx = cx(to) - cx(from); var dy = cy(to) - cy(from); var f = deltas[piece.kind]; if (!f || !f(piece, dx, dy, grid, to)) return false; if (piece.kind === 'knight') return true; return clearLine(from, to, grid); } return { canMove };