UNPKG

@publishvue/chessground

Version:
322 lines 11.3 kB
import { pos2key, key2pos, opposite, distanceSq, allPos, computeSquareCenter } from './util'; import { premove, queen, knight } from './premove'; export function callUserFunction(f, ...args) { if (f) setTimeout(() => f(...args), 1); } export function toggleOrientation(state) { state.orientation = opposite(state.orientation); state.animation.current = state.draggable.current = state.selected = undefined; } export function reset(state) { state.lastMove = undefined; unselect(state); unsetPremove(state); unsetPredrop(state); } export function setPieces(state, pieces) { for (const [key, piece] of pieces) { if (piece) state.pieces.set(key, piece); else state.pieces.delete(key); } } export function setCheck(state, color) { state.check = undefined; if (color === true) color = state.turnColor; if (color) for (const [k, p] of state.pieces) { if (p.role === 'king' && p.color === color) { state.check = k; } } } function setPremove(state, orig, dest, meta) { unsetPredrop(state); state.premovable.current = [orig, dest]; callUserFunction(state.premovable.events.set, orig, dest, meta); } export function unsetPremove(state) { if (state.premovable.current) { state.premovable.current = undefined; callUserFunction(state.premovable.events.unset); } } function setPredrop(state, role, key) { unsetPremove(state); state.predroppable.current = { role, key }; callUserFunction(state.predroppable.events.set, role, key); } export function unsetPredrop(state) { const pd = state.predroppable; if (pd.current) { pd.current = undefined; callUserFunction(pd.events.unset); } } function tryAutoCastle(state, orig, dest) { if (!state.autoCastle) return false; const king = state.pieces.get(orig); if (!king || king.role !== 'king') return false; const origPos = key2pos(orig); const destPos = key2pos(dest); if ((origPos[1] !== 0 && origPos[1] !== 7) || origPos[1] !== destPos[1]) return false; if (origPos[0] === 4 && !state.pieces.has(dest)) { if (destPos[0] === 6) dest = pos2key([7, destPos[1]]); else if (destPos[0] === 2) dest = pos2key([0, destPos[1]]); } const rook = state.pieces.get(dest); if (!rook || rook.color !== king.color || rook.role !== 'rook') return false; state.pieces.delete(orig); state.pieces.delete(dest); if (origPos[0] < destPos[0]) { state.pieces.set(pos2key([6, destPos[1]]), king); state.pieces.set(pos2key([5, destPos[1]]), rook); } else { state.pieces.set(pos2key([2, destPos[1]]), king); state.pieces.set(pos2key([3, destPos[1]]), rook); } return true; } export function baseMove(state, orig, dest) { const origPiece = state.pieces.get(orig), destPiece = state.pieces.get(dest); if (orig === dest || !origPiece) return false; const captured = destPiece && destPiece.color !== origPiece.color ? destPiece : undefined; if (dest === state.selected) unselect(state); callUserFunction(state.events.move, orig, dest, captured); if (!tryAutoCastle(state, orig, dest)) { state.pieces.set(dest, origPiece); state.pieces.delete(orig); } state.lastMove = [orig, dest]; state.check = undefined; callUserFunction(state.events.change); return captured || true; } export function baseNewPiece(state, piece, key, force) { if (state.pieces.has(key)) { if (force) state.pieces.delete(key); else return false; } callUserFunction(state.events.dropNewPiece, piece, key); state.pieces.set(key, piece); state.lastMove = [key]; state.check = undefined; callUserFunction(state.events.change); state.movable.dests = undefined; state.turnColor = opposite(state.turnColor); return true; } function baseUserMove(state, orig, dest) { const result = baseMove(state, orig, dest); if (result) { state.movable.dests = undefined; state.turnColor = opposite(state.turnColor); state.animation.current = undefined; } return result; } export function userMove(state, orig, dest) { if (canMove(state, orig, dest)) { const result = baseUserMove(state, orig, dest); if (result) { const holdTime = state.hold.stop(); unselect(state); const metadata = { premove: false, ctrlKey: state.stats.ctrlKey, holdTime, }; if (result !== true) metadata.captured = result; callUserFunction(state.movable.events.after, orig, dest, metadata); return true; } } else if (canPremove(state, orig, dest)) { setPremove(state, orig, dest, { ctrlKey: state.stats.ctrlKey, }); unselect(state); return true; } unselect(state); return false; } export function dropNewPiece(state, orig, dest, force) { const piece = state.pieces.get(orig); if (piece && (canDrop(state, orig, dest) || force)) { state.pieces.delete(orig); baseNewPiece(state, piece, dest, force); callUserFunction(state.movable.events.afterNewPiece, piece.role, dest, { premove: false, predrop: false, }); } else if (piece && canPredrop(state, orig, dest)) { setPredrop(state, piece.role, dest); } else { unsetPremove(state); unsetPredrop(state); } state.pieces.delete(orig); unselect(state); } export function selectSquare(state, key, force) { callUserFunction(state.events.select, key); if (state.selected) { if (state.selected === key && !state.draggable.enabled) { unselect(state); state.hold.cancel(); return; } else if ((state.selectable.enabled || force) && state.selected !== key) { if (userMove(state, state.selected, key)) { state.stats.dragged = false; return; } } } if (isMovable(state, key) || isPremovable(state, key)) { setSelected(state, key); state.hold.start(); } } export function setSelected(state, key) { state.selected = key; if (isPremovable(state, key)) { state.premovable.dests = premove(state.pieces, key, state.premovable.castle); } else state.premovable.dests = undefined; } export function unselect(state) { state.selected = undefined; state.premovable.dests = undefined; state.hold.cancel(); } function isMovable(state, orig) { const piece = state.pieces.get(orig); return (!!piece && (state.movable.color === 'both' || (state.movable.color === piece.color && state.turnColor === piece.color))); } export function canMove(state, orig, dest) { var _a, _b; return (orig !== dest && isMovable(state, orig) && (state.movable.free || !!((_b = (_a = state.movable.dests) === null || _a === void 0 ? void 0 : _a.get(orig)) === null || _b === void 0 ? void 0 : _b.includes(dest)))); } function canDrop(state, orig, dest) { const piece = state.pieces.get(orig); return (!!piece && (orig === dest || !state.pieces.has(dest)) && (state.movable.color === 'both' || (state.movable.color === piece.color && state.turnColor === piece.color))); } function isPremovable(state, orig) { const piece = state.pieces.get(orig); return !!piece && state.premovable.enabled && state.movable.color === piece.color && state.turnColor !== piece.color; } function canPremove(state, orig, dest) { return (orig !== dest && isPremovable(state, orig) && premove(state.pieces, orig, state.premovable.castle).includes(dest)); } function canPredrop(state, orig, dest) { const piece = state.pieces.get(orig); const destPiece = state.pieces.get(dest); return (!!piece && (!destPiece || destPiece.color !== state.movable.color) && state.predroppable.enabled && (piece.role !== 'pawn' || (dest[1] !== '1' && dest[1] !== '8')) && state.movable.color === piece.color && state.turnColor !== piece.color); } export function isDraggable(state, orig) { const piece = state.pieces.get(orig); return (!!piece && state.draggable.enabled && (state.movable.color === 'both' || (state.movable.color === piece.color && (state.turnColor === piece.color || state.premovable.enabled)))); } export function playPremove(state) { const move = state.premovable.current; if (!move) return false; const orig = move[0], dest = move[1]; let success = false; if (canMove(state, orig, dest)) { const result = baseUserMove(state, orig, dest); if (result) { const metadata = { premove: true }; if (result !== true) metadata.captured = result; callUserFunction(state.movable.events.after, orig, dest, metadata); success = true; } } unsetPremove(state); return success; } export function playPredrop(state, validate) { const drop = state.predroppable.current; let success = false; if (!drop) return false; if (validate(drop)) { const piece = { role: drop.role, color: state.movable.color, }; if (baseNewPiece(state, piece, drop.key)) { callUserFunction(state.movable.events.afterNewPiece, drop.role, drop.key, { premove: false, predrop: true, }); success = true; } } unsetPredrop(state); return success; } export function cancelMove(state) { unsetPremove(state); unsetPredrop(state); unselect(state); } export function stop(state) { state.movable.color = state.movable.dests = state.animation.current = undefined; cancelMove(state); } export function getKeyAtDomPos(pos, asWhite, bounds) { let file = Math.floor((8 * (pos[0] - bounds.left)) / bounds.width); if (!asWhite) file = 7 - file; let rank = 7 - Math.floor((8 * (pos[1] - bounds.top)) / bounds.height); if (!asWhite) rank = 7 - rank; return file >= 0 && file < 8 && rank >= 0 && rank < 8 ? pos2key([file, rank]) : undefined; } export function getSnappedKeyAtDomPos(orig, pos, asWhite, bounds) { const origPos = key2pos(orig); const validSnapPos = allPos.filter(pos2 => { return queen(origPos[0], origPos[1], pos2[0], pos2[1]) || knight(origPos[0], origPos[1], pos2[0], pos2[1]); }); const validSnapCenters = validSnapPos.map(pos2 => computeSquareCenter(pos2key(pos2), asWhite, bounds)); const validSnapDistances = validSnapCenters.map(pos2 => distanceSq(pos, pos2)); const [, closestSnapIndex] = validSnapDistances.reduce((a, b, index) => (a[0] < b ? a : [b, index]), [validSnapDistances[0], 0]); return pos2key(validSnapPos[closestSnapIndex]); } export function whitePov(s) { return s.orientation === 'white'; } //# sourceMappingURL=board.js.map