chessground-haichess
Version:
lichess.org Chess UI
1,357 lines • 285 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chessground = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.render = exports.anim = void 0;
const util = require("./util");
function anim(mutation, state) {
return state.animation.enabled ? animate(mutation, state) : render(mutation, state);
}
exports.anim = anim;
function render(mutation, state) {
const result = mutation(state);
state.dom.redraw();
return result;
}
exports.render = render;
function makePiece(key, piece) {
return {
key: key,
pos: util.key2pos(key),
piece: piece,
};
}
function closer(piece, pieces) {
return pieces.sort((p1, p2) => {
return util.distanceSq(piece.pos, p1.pos) - util.distanceSq(piece.pos, p2.pos);
})[0];
}
function computePlan(prevPieces, current) {
const anims = new Map(), animedOrigs = [], fadings = new Map(), missings = [], news = [], prePieces = new Map();
let curP, preP, vector;
for (const [k, p] of prevPieces) {
prePieces.set(k, makePiece(k, p));
}
for (const key of util.allKeys) {
curP = current.pieces.get(key);
preP = prePieces.get(key);
if (curP) {
if (preP) {
if (!util.samePiece(curP, preP.piece)) {
missings.push(preP);
news.push(makePiece(key, curP));
}
}
else
news.push(makePiece(key, curP));
}
else if (preP)
missings.push(preP);
}
for (const newP of news) {
preP = closer(newP, missings.filter(p => util.samePiece(newP.piece, p.piece)));
if (preP) {
vector = [preP.pos[0] - newP.pos[0], preP.pos[1] - newP.pos[1]];
anims.set(newP.key, vector.concat(vector));
animedOrigs.push(preP.key);
}
}
for (const p of missings) {
if (animedOrigs.indexOf(p.key) === -1)
fadings.set(p.key, p.piece);
}
return {
anims: anims,
fadings: fadings,
};
}
function step(state, now) {
const cur = state.animation.current;
if (cur === undefined) {
if (!state.dom.destroyed)
state.dom.redrawNow();
return;
}
const rest = 1 - (now - cur.start) * cur.frequency;
if (rest <= 0) {
state.animation.current = undefined;
state.dom.redrawNow();
}
else {
const ease = easing(rest);
for (const cfg of cur.plan.anims.values()) {
cfg[2] = cfg[0] * ease;
cfg[3] = cfg[1] * ease;
}
state.dom.redrawNow(true);
requestAnimationFrame((now = performance.now()) => step(state, now));
}
}
function animate(mutation, state) {
const prevPieces = new Map(state.pieces);
const result = mutation(state);
const plan = computePlan(prevPieces, state);
if (plan.anims.size || plan.fadings.size) {
const alreadyRunning = state.animation.current && state.animation.current.start;
state.animation.current = {
start: performance.now(),
frequency: 1 / state.animation.duration,
plan: plan,
};
if (!alreadyRunning)
step(state, performance.now());
}
else {
state.dom.redraw();
}
return result;
}
function easing(t) {
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
}
},{"./util":18}],2:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.start = void 0;
const board = require("./board");
const fen_1 = require("./fen");
const config_1 = require("./config");
const anim_1 = require("./anim");
const drag_1 = require("./drag");
const explosion_1 = require("./explosion");
function start(state, redrawAll) {
function toggleOrientation() {
board.toggleOrientation(state);
redrawAll();
}
return {
set(config) {
if (config.orientation && config.orientation !== state.orientation)
toggleOrientation();
(config.fen ? anim_1.anim : anim_1.render)(state => config_1.configure(state, config), state);
},
state,
getFen: () => fen_1.write(state.pieces),
toggleOrientation,
setPieces(pieces) {
anim_1.anim(state => board.setPieces(state, pieces), state);
},
selectSquare(key, force) {
if (key)
anim_1.anim(state => board.selectSquare(state, key, force), state);
else if (state.selected) {
board.unselect(state);
state.dom.redraw();
}
},
move(orig, dest) {
anim_1.anim(state => board.baseMove(state, orig, dest), state);
},
newPiece(piece, key) {
anim_1.anim(state => board.baseNewPiece(state, piece, key), state);
},
playPremove() {
if (state.premovable.current) {
if (anim_1.anim(board.playPremove, state))
return true;
state.dom.redraw();
}
return false;
},
playPredrop(validate) {
if (state.predroppable.current) {
const result = board.playPredrop(state, validate);
state.dom.redraw();
return result;
}
return false;
},
cancelPremove() {
anim_1.render(board.unsetPremove, state);
},
cancelPredrop() {
anim_1.render(board.unsetPredrop, state);
},
cancelMove() {
anim_1.render(state => {
board.cancelMove(state);
drag_1.cancel(state);
}, state);
},
stop() {
anim_1.render(state => {
board.stop(state);
drag_1.cancel(state);
}, state);
},
explode(keys) {
explosion_1.explosion(state, keys);
},
setAutoShapes(shapes) {
anim_1.render(state => (state.drawable.autoShapes = shapes), state);
},
setShapes(shapes) {
anim_1.render(state => (state.drawable.shapes = shapes), state);
},
getKeyAtDomPos(pos) {
return board.getKeyAtDomPos(pos, board.whitePov(state), state.dom.bounds());
},
redrawAll,
dragNewPiece(piece, event, force) {
drag_1.dragNewPiece(state, piece, event, force);
},
destroy() {
board.stop(state);
state.dom.unbind && state.dom.unbind();
state.dom.destroyed = true;
},
};
}
exports.start = start;
},{"./anim":1,"./board":3,"./config":5,"./drag":6,"./explosion":10,"./fen":11}],3:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.whitePov = exports.getSnappedKeyAtDomPos = exports.getKeyAtDomPos = exports.stop = exports.cancelMove = exports.playPredrop = exports.playPremove = exports.isDraggable = exports.canMove = exports.unselect = exports.setSelected = exports.selectSquare = exports.dropNewPiece = exports.userMove = exports.baseNewPiece = exports.baseMove = exports.unsetPredrop = exports.unsetPremove = exports.setCheck = exports.setPieces = exports.reset = exports.toggleOrientation = exports.callUserFunction = void 0;
const util_1 = require("./util");
const premove_1 = require("./premove");
function callUserFunction(f, ...args) {
if (f)
setTimeout(() => f(...args), 1);
}
exports.callUserFunction = callUserFunction;
function toggleOrientation(state) {
state.orientation = util_1.opposite(state.orientation);
state.animation.current = state.draggable.current = state.selected = undefined;
}
exports.toggleOrientation = toggleOrientation;
function reset(state) {
state.lastMove = undefined;
unselect(state);
unsetPremove(state);
unsetPredrop(state);
}
exports.reset = reset;
function setPieces(state, pieces) {
for (const [key, piece] of pieces) {
if (piece)
state.pieces.set(key, piece);
else
state.pieces.delete(key);
}
}
exports.setPieces = setPieces;
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;
}
}
}
exports.setCheck = setCheck;
function setPremove(state, orig, dest, meta) {
unsetPredrop(state);
state.premovable.current = [orig, dest];
callUserFunction(state.premovable.events.set, orig, dest, meta);
}
function unsetPremove(state) {
if (state.premovable.current) {
state.premovable.current = undefined;
callUserFunction(state.premovable.events.unset);
}
}
exports.unsetPremove = unsetPremove;
function setPredrop(state, role, key) {
unsetPremove(state);
state.predroppable.current = { role, key };
callUserFunction(state.predroppable.events.set, role, key);
}
function unsetPredrop(state) {
const pd = state.predroppable;
if (pd.current) {
pd.current = undefined;
callUserFunction(pd.events.unset);
}
}
exports.unsetPredrop = unsetPredrop;
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 = util_1.key2pos(orig);
const destPos = util_1.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 = util_1.pos2key([7, destPos[1]]);
else if (destPos[0] === 2)
dest = util_1.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(util_1.pos2key([6, destPos[1]]), king);
state.pieces.set(util_1.pos2key([5, destPos[1]]), rook);
}
else {
state.pieces.set(util_1.pos2key([2, destPos[1]]), king);
state.pieces.set(util_1.pos2key([3, destPos[1]]), rook);
}
return true;
}
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;
}
exports.baseMove = baseMove;
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 = util_1.opposite(state.turnColor);
return true;
}
exports.baseNewPiece = baseNewPiece;
function baseUserMove(state, orig, dest) {
const result = baseMove(state, orig, dest);
if (result) {
state.movable.dests = undefined;
state.turnColor = util_1.opposite(state.turnColor);
state.animation.current = undefined;
}
return result;
}
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;
}
exports.userMove = userMove;
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);
}
exports.dropNewPiece = dropNewPiece;
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();
}
}
exports.selectSquare = selectSquare;
function setSelected(state, key) {
state.selected = key;
if (isPremovable(state, key)) {
state.premovable.dests = premove_1.premove(state.pieces, key, state.premovable.castle);
}
else
state.premovable.dests = undefined;
}
exports.setSelected = setSelected;
function unselect(state) {
state.selected = undefined;
state.premovable.dests = undefined;
state.hold.cancel();
}
exports.unselect = unselect;
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)));
}
function canMove(state, orig, dest) {
var _a, _b;
return (orig !== dest && isMovable(state, orig) && (state.movable.free || (!!state.movable.dests && !!state.movable.dests.get(orig) && ((_b = (_a = state.movable.dests) === null || _a === void 0 ? void 0 : _a.get(orig)) === null || _b === void 0 ? void 0 : _b.indexOf(dest)) !== -1)));
}
exports.canMove = canMove;
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_1.premove(state.pieces, orig, state.premovable.castle).indexOf(dest) !== -1);
}
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);
}
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))));
}
exports.isDraggable = isDraggable;
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;
}
exports.playPremove = playPremove;
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;
}
exports.playPredrop = playPredrop;
function cancelMove(state) {
unsetPremove(state);
unsetPredrop(state);
unselect(state);
}
exports.cancelMove = cancelMove;
function stop(state) {
state.movable.color = state.movable.dests = state.animation.current = undefined;
cancelMove(state);
}
exports.stop = stop;
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 ? util_1.pos2key([file, rank]) : undefined;
}
exports.getKeyAtDomPos = getKeyAtDomPos;
function getSnappedKeyAtDomPos(orig, pos, asWhite, bounds) {
const origPos = util_1.key2pos(orig);
const validSnapPos = util_1.allPos.filter(pos2 => {
return premove_1.queen(origPos[0], origPos[1], pos2[0], pos2[1]) || premove_1.knight(origPos[0], origPos[1], pos2[0], pos2[1]);
});
const validSnapCenters = validSnapPos.map(pos2 => util_1.computeSquareCenter(util_1.pos2key(pos2), asWhite, bounds));
const validSnapDistances = validSnapCenters.map(pos2 => util_1.distanceSq(pos, pos2));
const [, closestSnapIndex] = validSnapDistances.reduce((a, b, index) => (a[0] < b ? a : [b, index]), [
validSnapDistances[0],
0,
]);
return util_1.pos2key(validSnapPos[closestSnapIndex]);
}
exports.getSnappedKeyAtDomPos = getSnappedKeyAtDomPos;
function whitePov(s) {
return s.orientation === 'white';
}
exports.whitePov = whitePov;
},{"./premove":13,"./util":18}],4:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Chessground = void 0;
const api_1 = require("./api");
const config_1 = require("./config");
const state_1 = require("./state");
const wrap_1 = require("./wrap");
const events = require("./events");
const render_1 = require("./render");
const svg = require("./svg");
const util = require("./util");
function Chessground(element, config) {
const maybeState = state_1.defaults();
config_1.configure(maybeState, config || {});
function redrawAll() {
const prevUnbind = 'dom' in maybeState ? maybeState.dom.unbind : undefined;
const relative = maybeState.viewOnly && !maybeState.drawable.visible, elements = wrap_1.renderWrap(element, maybeState, relative), bounds = util.memo(() => elements.board.getBoundingClientRect()), redrawNow = (skipSvg) => {
render_1.render(state);
if (!skipSvg && elements.svg)
svg.renderSvg(state, elements.svg, elements.customSvg);
}, boundsUpdated = () => {
bounds.clear();
render_1.updateBounds(state);
if (elements.svg)
svg.renderSvg(state, elements.svg, elements.customSvg);
};
const state = maybeState;
state.dom = {
elements,
bounds,
redraw: debounceRedraw(redrawNow),
redrawNow,
unbind: prevUnbind,
relative,
};
state.drawable.prevSvgHash = '';
redrawNow(false);
events.bindBoard(state, boundsUpdated);
if (!prevUnbind)
state.dom.unbind = events.bindDocument(state, boundsUpdated);
state.events.insert && state.events.insert(elements);
return state;
}
return api_1.start(redrawAll(), redrawAll);
}
exports.Chessground = Chessground;
function debounceRedraw(redrawNow) {
let redrawing = false;
return () => {
if (redrawing)
return;
redrawing = true;
requestAnimationFrame(() => {
redrawNow();
redrawing = false;
});
};
}
},{"./api":2,"./config":5,"./events":9,"./render":14,"./state":15,"./svg":16,"./util":18,"./wrap":19}],5:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.configure = void 0;
const board_1 = require("./board");
const fen_1 = require("./fen");
function configure(state, config) {
var _a, _b;
if ((_a = config.movable) === null || _a === void 0 ? void 0 : _a.dests)
state.movable.dests = undefined;
if ((_b = config.drawable) === null || _b === void 0 ? void 0 : _b.autoShapes)
state.drawable.autoShapes = [];
merge(state, config);
if (config.fen) {
state.pieces = fen_1.read(config.fen);
state.drawable.shapes = [];
}
if ('check' in config)
board_1.setCheck(state, config.check || false);
if ('lastMove' in config && !config.lastMove)
state.lastMove = undefined;
else if (config.lastMove)
state.lastMove = config.lastMove;
if (state.selected)
board_1.setSelected(state, state.selected);
if (!state.animation.duration || state.animation.duration < 100)
state.animation.enabled = false;
if (!state.movable.rookCastle && state.movable.dests) {
const rank = state.movable.color === 'white' ? '1' : '8', kingStartPos = ('e' + rank), dests = state.movable.dests.get(kingStartPos), king = state.pieces.get(kingStartPos);
if (!dests || !king || king.role !== 'king')
return;
state.movable.dests.set(kingStartPos, dests.filter(d => !(d === 'a' + rank && dests.indexOf(('c' + rank)) !== -1) &&
!(d === 'h' + rank && dests.indexOf(('g' + rank)) !== -1)));
}
}
exports.configure = configure;
function merge(base, extend) {
for (const key in extend) {
if (isObject(base[key]) && isObject(extend[key]))
merge(base[key], extend[key]);
else
base[key] = extend[key];
}
}
function isObject(o) {
return typeof o === 'object';
}
},{"./board":3,"./fen":11}],6:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.cancel = exports.end = exports.move = exports.dragNewPiece = exports.start = void 0;
const board = require("./board");
const util = require("./util");
const draw_1 = require("./draw");
const anim_1 = require("./anim");
function start(s, e) {
if (!e.isTrusted || (e.button !== undefined && e.button !== 0))
return;
if (e.touches && e.touches.length > 1)
return;
const bounds = s.dom.bounds(), position = util.eventPosition(e), orig = board.getKeyAtDomPos(position, board.whitePov(s), bounds);
if (!orig)
return;
const piece = s.pieces.get(orig);
const previouslySelected = s.selected;
if (!previouslySelected && s.drawable.enabled && (s.drawable.eraseOnClick || !piece || piece.color !== s.turnColor))
draw_1.clear(s);
if (e.cancelable !== false &&
(!e.touches || !s.movable.color || piece || previouslySelected || pieceCloseTo(s, position)))
e.preventDefault();
const hadPremove = !!s.premovable.current;
const hadPredrop = !!s.predroppable.current;
s.stats.ctrlKey = e.ctrlKey;
if (s.selected && board.canMove(s, s.selected, orig)) {
anim_1.anim(state => board.selectSquare(state, orig), s);
}
else {
board.selectSquare(s, orig);
}
const stillSelected = s.selected === orig;
const element = pieceElementByKey(s, orig);
if (piece && element && stillSelected && board.isDraggable(s, orig)) {
s.draggable.current = {
orig,
piece,
origPos: position,
pos: position,
started: s.draggable.autoDistance && s.stats.dragged,
element,
previouslySelected,
originTarget: e.target,
};
element.cgDragging = true;
element.classList.add('dragging');
const ghost = s.dom.elements.ghost;
if (ghost) {
ghost.className = `ghost ${piece.color} ${piece.role}`;
util.translateAbs(ghost, util.posToTranslateAbs(bounds)(util.key2pos(orig), board.whitePov(s)));
util.setVisible(ghost, true);
}
processDrag(s);
}
else {
if (hadPremove)
board.unsetPremove(s);
if (hadPredrop)
board.unsetPredrop(s);
}
s.dom.redraw();
}
exports.start = start;
function pieceCloseTo(s, pos) {
const asWhite = board.whitePov(s), bounds = s.dom.bounds(), radiusSq = Math.pow(bounds.width / 8, 2);
for (const key in s.pieces) {
const center = util.computeSquareCenter(key, asWhite, bounds);
if (util.distanceSq(center, pos) <= radiusSq)
return true;
}
return false;
}
function dragNewPiece(s, piece, e, force) {
const key = 'a0';
s.pieces.set(key, piece);
s.dom.redraw();
const position = util.eventPosition(e);
s.draggable.current = {
orig: key,
piece,
origPos: position,
pos: position,
started: true,
element: () => pieceElementByKey(s, key),
originTarget: e.target,
newPiece: true,
force: !!force,
};
processDrag(s);
}
exports.dragNewPiece = dragNewPiece;
function processDrag(s) {
requestAnimationFrame(() => {
var _a;
const cur = s.draggable.current;
if (!cur)
return;
if ((_a = s.animation.current) === null || _a === void 0 ? void 0 : _a.plan.anims.has(cur.orig))
s.animation.current = undefined;
const origPiece = s.pieces.get(cur.orig);
if (!origPiece || !util.samePiece(origPiece, cur.piece))
cancel(s);
else {
if (!cur.started && util.distanceSq(cur.pos, cur.origPos) >= Math.pow(s.draggable.distance, 2))
cur.started = true;
if (cur.started) {
if (typeof cur.element === 'function') {
const found = cur.element();
if (!found)
return;
found.cgDragging = true;
found.classList.add('dragging');
cur.element = found;
}
const bounds = s.dom.bounds();
util.translateAbs(cur.element, [
cur.pos[0] - bounds.left - bounds.width / 16,
cur.pos[1] - bounds.top - bounds.height / 16,
]);
}
}
processDrag(s);
});
}
function move(s, e) {
if (s.draggable.current && (!e.touches || e.touches.length < 2)) {
s.draggable.current.pos = util.eventPosition(e);
}
}
exports.move = move;
function end(s, e) {
const cur = s.draggable.current;
if (!cur)
return;
if (e.type === 'touchend' && e.cancelable !== false)
e.preventDefault();
if (e.type === 'touchend' && cur.originTarget !== e.target && !cur.newPiece) {
s.draggable.current = undefined;
return;
}
board.unsetPremove(s);
board.unsetPredrop(s);
const eventPos = util.eventPosition(e) || cur.pos;
const dest = board.getKeyAtDomPos(eventPos, board.whitePov(s), s.dom.bounds());
if (dest && cur.started && cur.orig !== dest) {
if (cur.newPiece)
board.dropNewPiece(s, cur.orig, dest, cur.force);
else {
s.stats.ctrlKey = e.ctrlKey;
if (board.userMove(s, cur.orig, dest))
s.stats.dragged = true;
}
}
else if (cur.newPiece) {
s.pieces.delete(cur.orig);
}
else if (s.draggable.deleteOnDropOff && !dest) {
s.pieces.delete(cur.orig);
board.callUserFunction(s.events.change);
}
if (cur.orig === cur.previouslySelected && (cur.orig === dest || !dest))
board.unselect(s);
else if (!s.selectable.enabled)
board.unselect(s);
removeDragElements(s);
s.draggable.current = undefined;
s.dom.redraw();
}
exports.end = end;
function cancel(s) {
const cur = s.draggable.current;
if (cur) {
if (cur.newPiece)
s.pieces.delete(cur.orig);
s.draggable.current = undefined;
board.unselect(s);
removeDragElements(s);
s.dom.redraw();
}
}
exports.cancel = cancel;
function removeDragElements(s) {
const e = s.dom.elements;
if (e.ghost)
util.setVisible(e.ghost, false);
}
function pieceElementByKey(s, key) {
let el = s.dom.elements.board.firstChild;
while (el) {
if (el.cgKey === key && el.tagName === 'PIECE')
return el;
el = el.nextSibling;
}
return;
}
},{"./anim":1,"./board":3,"./draw":7,"./util":18}],7:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.clear = exports.cancel = exports.end = exports.move = exports.processDraw = exports.start = void 0;
const board_1 = require("./board");
const util_1 = require("./util");
const brushes = ['green', 'red', 'blue', 'yellow'];
function start(state, e) {
if (e.touches && e.touches.length > 1)
return;
e.stopPropagation();
e.preventDefault();
e.ctrlKey ? board_1.unselect(state) : board_1.cancelMove(state);
const pos = util_1.eventPosition(e), orig = board_1.getKeyAtDomPos(pos, board_1.whitePov(state), state.dom.bounds());
if (!orig)
return;
state.drawable.current = {
orig,
pos,
brush: eventBrush(e),
snapToValidMove: state.drawable.defaultSnapToValidMove,
};
processDraw(state);
}
exports.start = start;
function processDraw(state) {
requestAnimationFrame(() => {
const cur = state.drawable.current;
if (cur) {
const keyAtDomPos = board_1.getKeyAtDomPos(cur.pos, board_1.whitePov(state), state.dom.bounds());
if (!keyAtDomPos) {
cur.snapToValidMove = false;
}
const mouseSq = cur.snapToValidMove
? board_1.getSnappedKeyAtDomPos(cur.orig, cur.pos, board_1.whitePov(state), state.dom.bounds())
: keyAtDomPos;
if (mouseSq !== cur.mouseSq) {
cur.mouseSq = mouseSq;
cur.dest = mouseSq !== cur.orig ? mouseSq : undefined;
state.dom.redrawNow();
}
processDraw(state);
}
});
}
exports.processDraw = processDraw;
function move(state, e) {
if (state.drawable.current)
state.drawable.current.pos = util_1.eventPosition(e);
}
exports.move = move;
function end(state) {
const cur = state.drawable.current;
if (cur) {
if (cur.mouseSq)
addShape(state.drawable, cur);
cancel(state);
}
}
exports.end = end;
function cancel(state) {
if (state.drawable.current) {
state.drawable.current = undefined;
state.dom.redraw();
}
}
exports.cancel = cancel;
function clear(state) {
if (state.drawable.shapes.length) {
state.drawable.shapes = [];
state.dom.redraw();
onChange(state.drawable);
}
}
exports.clear = clear;
function eventBrush(e) {
var _a;
const modA = (e.shiftKey || e.ctrlKey) && util_1.isRightButton(e);
const modB = e.altKey || e.metaKey || ((_a = e.getModifierState) === null || _a === void 0 ? void 0 : _a.call(e, 'AltGraph'));
return brushes[(modA ? 1 : 0) + (modB ? 2 : 0)];
}
function addShape(drawable, cur) {
const sameShape = (s) => s.orig === cur.orig && s.dest === cur.dest;
const similar = drawable.shapes.find(sameShape);
if (similar)
drawable.shapes = drawable.shapes.filter(s => !sameShape(s));
if (!similar || similar.brush !== cur.brush)
drawable.shapes.push(cur);
onChange(drawable);
}
function onChange(drawable) {
if (drawable.onChange)
drawable.onChange(drawable.shapes);
}
},{"./board":3,"./util":18}],8:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.drop = exports.cancelDropMode = exports.setDropMode = void 0;
const board = require("./board");
const util = require("./util");
const drag_1 = require("./drag");
function setDropMode(s, piece) {
s.dropmode = {
active: true,
piece,
};
drag_1.cancel(s);
}
exports.setDropMode = setDropMode;
function cancelDropMode(s) {
s.dropmode = {
active: false,
};
}
exports.cancelDropMode = cancelDropMode;
function drop(s, e) {
if (!s.dropmode.active)
return;
board.unsetPremove(s);
board.unsetPredrop(s);
const piece = s.dropmode.piece;
if (piece) {
s.pieces.set('a0', piece);
const position = util.eventPosition(e);
const dest = position && board.getKeyAtDomPos(position, board.whitePov(s), s.dom.bounds());
if (dest)
board.dropNewPiece(s, 'a0', dest);
}
s.dom.redraw();
}
exports.drop = drop;
},{"./board":3,"./drag":6,"./util":18}],9:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.bindDocument = exports.bindBoard = void 0;
const drag = require("./drag");
const draw = require("./draw");
const drop_1 = require("./drop");
const util_1 = require("./util");
function bindBoard(s, boundsUpdated) {
const boardEl = s.dom.elements.board;
if (!s.dom.relative && s.resizable && 'ResizeObserver' in window) {
const observer = new window['ResizeObserver'](boundsUpdated);
observer.observe(boardEl);
}
if (s.viewOnly)
return;
const onStart = startDragOrDraw(s);
boardEl.addEventListener('touchstart', onStart, {
passive: false,
});
boardEl.addEventListener('mousedown', onStart, {
passive: false,
});
if (s.disableContextMenu || s.drawable.enabled) {
boardEl.addEventListener('contextmenu', e => e.preventDefault());
}
}
exports.bindBoard = bindBoard;
function bindDocument(s, boundsUpdated) {
const unbinds = [];
if (!s.dom.relative && s.resizable && !('ResizeObserver' in window)) {
unbinds.push(unbindable(document.body, 'chessground.resize', boundsUpdated));
}
if (!s.viewOnly) {
const onmove = dragOrDraw(s, drag.move, draw.move);
const onend = dragOrDraw(s, drag.end, draw.end);
for (const ev of ['touchmove', 'mousemove'])
unbinds.push(unbindable(document, ev, onmove));
for (const ev of ['touchend', 'mouseup'])
unbinds.push(unbindable(document, ev, onend));
const onScroll = () => s.dom.bounds.clear();
unbinds.push(unbindable(document, 'scroll', onScroll, { capture: true, passive: true }));
unbinds.push(unbindable(window, 'resize', onScroll, { passive: true }));
}
return () => unbinds.forEach(f => f());
}
exports.bindDocument = bindDocument;
function unbindable(el, eventName, callback, options) {
el.addEventListener(eventName, callback, options);
return () => el.removeEventListener(eventName, callback, options);
}
function startDragOrDraw(s) {
return e => {
if (s.draggable.current)
drag.cancel(s);
else if (s.drawable.current)
draw.cancel(s);
else if (e.shiftKey || util_1.isRightButton(e)) {
if (s.drawable.enabled)
draw.start(s, e);
}
else if (!s.viewOnly) {
if (s.dropmode.active)
drop_1.drop(s, e);
else
drag.start(s, e);
}
};
}
function dragOrDraw(s, withDrag, withDraw) {
return e => {
if (s.drawable.current) {
if (s.drawable.enabled)
withDraw(s, e);
}
else if (!s.viewOnly)
withDrag(s, e);
};
}
},{"./drag":6,"./draw":7,"./drop":8,"./util":18}],10:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.explosion = void 0;
function explosion(state, keys) {
state.exploding = { stage: 1, keys };
state.dom.redraw();
setTimeout(() => {
setStage(state, 2);
setTimeout(() => setStage(state, undefined), 120);
}, 120);
}
exports.explosion = explosion;
function setStage(state, stage) {
if (state.exploding) {
if (stage)
state.exploding.stage = stage;
else
state.exploding = undefined;
state.dom.redraw();
}
}
},{}],11:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.write = exports.read = exports.initial = void 0;
const util_1 = require("./util");
const cg = require("./types");
exports.initial = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR';
const roles = {
p: 'pawn',
r: 'rook',
n: 'knight',
b: 'bishop',
q: 'queen',
k: 'king',
};
const letters = {
pawn: 'p',
rook: 'r',
knight: 'n',
bishop: 'b',
queen: 'q',
king: 'k',
};
function read(fen) {
if (fen === 'start')
fen = exports.initial;
const pieces = new Map();
let row = 7, col = 0;
for (const c of fen) {
switch (c) {
case ' ':
return pieces;
case '/':
--row;
if (row < 0)
return pieces;
col = 0;
break;
case '~': {
const piece = pieces.get(util_1.pos2key([col, row]));
if (piece)
piece.promoted = true;
break;
}
default: {
const nb = c.charCodeAt(0);
if (nb < 57)
col += nb - 48;
else {
const role = c.toLowerCase();
pieces.set(util_1.pos2key([col, row]), {
role: roles[role],
color: c === role ? 'black' : 'white',
});
++col;
}
}
}
}
return pieces;
}
exports.read = read;
function write(pieces) {
return util_1.invRanks
.map(y => cg.files
.map(x => {
const piece = pieces.get((x + y));
if (piece) {
const letter = letters[piece.role];
return piece.color === 'white' ? letter.toUpperCase() : letter;
}
else
return '1';
})
.join(''))
.join('/')
.replace(/1{2,}/g, s => s.length.toString());
}
exports.write = write;
},{"./types":17,"./util":18}],12:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chessground_1 = require("./chessground");
exports.default = chessground_1.Chessground;
},{"./chessground":4}],13:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.premove = exports.queen = exports.knight = void 0;
const util = require("./util");
function diff(a, b) {
return Math.abs(a - b);
}
function pawn(color) {
return (x1, y1, x2, y2) => diff(x1, x2) < 2 &&
(color === 'white'
?
y2 === y1 + 1 || (y1 <= 1 && y2 === y1 + 2 && x1 === x2)
: y2 === y1 - 1 || (y1 >= 6 && y2 === y1 - 2 && x1 === x2));
}
exports.knight = (x1, y1, x2, y2) => {
const xd = diff(x1, x2);
const yd = diff(y1, y2);
return (xd === 1 && yd === 2) || (xd === 2 && yd === 1);
};
const bishop = (x1, y1, x2, y2) => {
return diff(x1, x2) === diff(y1, y2);
};
const rook = (x1, y1, x2, y2) => {
return x1 === x2 || y1 === y2;
};
exports.queen = (x1, y1, x2, y2) => {
return bishop(x1, y1, x2, y2) || rook(x1, y1, x2, y2);
};
function king(color, rookFiles, canCastle) {
return (x1, y1, x2, y2) => (diff(x1, x2) < 2 && diff(y1, y2) < 2) ||
(canCastle &&
y1 === y2 &&
y1 === (color === 'white' ? 0 : 7) &&
((x1 === 4 && ((x2 === 2 && rookFiles.indexOf(0) !== -1) || (x2 === 6 && rookFiles.indexOf(7) !== -1))) ||
rookFiles.indexOf(x2) !== -1));
}
function rookFilesOf(pieces, color) {
const backrank = color === 'white' ? '1' : '8';
const files = [];
for (const [key, piece] of pieces) {
if (key[1] === backrank && piece.color === color && piece.role === 'rook') {
files.push(util.key2pos(key)[0]);
}
}
return files;
}
function premove(pieces, key, canCastle) {
const piece = pieces.get(key);
if (!piece)
return [];
const pos = util.key2pos(key), r = piece.role, mobility = r === 'pawn'
? pawn(piece.color)
: r === 'knight'
? exports.knight
: r === 'bishop'
? bishop
: r === 'rook'
? rook
: r === 'queen'
? exports.queen
: king(piece.color, rookFilesOf(pieces, piece.color), canCastle);
return util.allPos
.filter(pos2 => (pos[0] !== pos2[0] || pos[1] !== pos2[1]) && mobility(pos[0], pos[1], pos2[0], pos2[1]))
.map(util.pos2key);
}
exports.premove = premove;
},{"./util":18}],14:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateBounds = exports.render = void 0;
const util_1 = require("./util");
const board_1 = require("./board");
function render(s) {
const asWhite = board_1.whitePov(s), posToTranslate = s.dom.relative ? util_1.posToTranslateRel : util_1.posToTranslateAbs(s.dom.bounds()), translate = s.dom.relative ? util_1.translateRel : util_1.translateAbs, boardEl = s.dom.elements.board, pieces = s.pieces, curAnim = s.animation.current, anims = curAnim ? curAnim.plan.anims : new Map(), fadings = curAnim ? curAnim.plan.fadings : new Map(), curDrag = s.draggable.current, squares = computeSquareClasses(s), samePieces = new Set(), sameSquares = new Set(), movedPieces = new Map(), movedSquares = new Map();
let k, el, pieceAtKey, elPieceName, anim, fading, pMvdset, pMvd, sMvdset, sMvd;
el = boardEl.firstChild;
while (el) {
k = el.cgKey;
if (isPieceNode(el)) {
pieceAtKey = pieces.get(k);
anim = anims.get(k);
fading = fadings.get(k);
elPieceName = el.cgPiece;
if (el.cgDragging && (!curDrag || curDrag.orig !== k)) {
el.classList.remove('dragging');
translate(el, posToTranslate(util_1.key2pos(k), asWhite));
el.cgDragging = false;
}
if (!fading && el.cgFading) {
el.cgFading = false;
el.classList.remove('fading');
}
if (pieceAtKey) {
if (anim && el.cgAnimating && elPieceName === pieceNameOf(pieceAtKey)) {
const pos = util_1.key2pos(k);
pos[0] += anim[2];
pos[1] += anim[3];
el.classList.add('anim');
translate(el, posToTranslate(pos, asWhite));
}
else if (el.cgAnimating) {
el.cgAnimating = false;
el.classList.remove('anim');
translate(el, posToTranslate(util_1.key2pos(k), asWhite));
if (s.addPieceZIndex)
el.style.zIndex = posZIndex(util_1.key2pos(k), asWhite);
}
if (elPieceName === pieceNameOf(pieceAtKey) && (!fading || !el.cgFading)) {
samePieces.add(k);
}
else {
if (fading && elPieceName === pieceNameOf(fading)) {
el.classList.add('fading');
el.cgFading = true;
}
else {
appendValue(movedPieces, elPieceName, el);
}
}
}
else {
appendValue(movedPieces, elPieceName, el);
}
}
else if (isSquareNode(el)) {
const cn = el.className;
if (squares.get(k) === cn)
sameSquares.add(k);
else
appendValue(movedSquares, cn, el);
}
el = el.nextSibling;
}
for (const [sk, className] of squares) {
if (!sameSquares.has(sk)) {
sMvdset = movedSquares.get(className);
sMvd = sMvdset && sMvdset.pop();
const translation = posToTranslate(util_1.key2pos(sk), asWhite);
if (sMvd) {
sMvd.cgKey = sk;
translate(sMvd, translation);
}
else {
const squareNode = util_1.createEl('square', className);
squareNode.cgKey = sk;
translate(squareNode, translation);
boardEl.insertBefore(squareNode, boardEl.firstChild);
}
}
}
for (const [k, p] of pieces) {
anim = anims.get(k);
if (!samePieces.has(k)) {
pMvdset = movedPieces.get(pieceNameOf(p));
pMvd = pMvdset && pMvdset.pop();
if (pMvd) {
pMvd.cgKey = k;
if (pMvd.cgFading) {
pMvd.classList.remove('fading');
pMvd.cgFading = false;
}
const pos = util_1.key2pos(k);
if (s.addPieceZIndex)
pMvd.style.zIndex = posZIndex(pos, asWhite);
if (anim) {
pMvd.cgAnimating = true;
pMvd.classList.add('anim');
pos[0] += anim[2];
pos[1] += anim[3];
}
translate(pMvd, posToTranslate(pos, asWhite));
}
else {
const pieceName = pieceNameOf(p), pieceNode = util_1.createEl('piece', pieceName), pos = util_1.key2pos(k);
pieceNode.cgPiece = pieceName;
pieceNode.cgKey = k;
if (anim) {
pieceNode.cg