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