+ static ParseFen(fen) {
+ return Object.assign(
+ ChessRules.ParseFen(fen),
+ { cmove: fen.split(" ")[4] }
+ );
+ }
+
+ static IsGoodFen(fen) {
+ if (!ChessRules.IsGoodFen(fen)) return false;
+ const fenParts = fen.split(" ");
+ if (fenParts.length != 6) return false;
+ if (fenParts[5] != "-" && !fenParts[5].match(/^([a-h][1-8]){2}$/))
+ return false;
+ return true;
+ }
+
+ getAmove(move) {
+ if (move.appear.length == 2 && move.vanish.length == 2)
+ return { appear: move.appear, vanish: move.vanish };
+ return null;
+ }
+
+ // TODO: this.firstMove + rooks location in setOtherVariables
+ // only rooks location in FEN (firstMove is forgotten if quit game and come back)
+ doClick(square) {
+ // If subTurn == 2 && square is the final square of last move,
+ // then return an empty move
+ if (
+ this.subTurn == 2 &&
+ square.x == this.firstMove.end.x &&
+ square.y == this.firstMove.end.y)
+ ) {
+ return {
+ appear: [],
+ vanish: []
+ };
+ }
+ return null;
+ }
+
+ canTake() {
+ // Captures don't occur (only pulls & pushes)
+ return false;
+ }
+
+ // "pa" : piece (as a square) doing this push/pull action
+ getActionMoves([sx, sy], [ex, ey], pa) {
+ const color = this.getColor(sx, sy);
+ const lastRank = (color == 'w' ? 0 : 7);
+ const piece = this.getPiece(sx, sy);
+ let moves = [];
+ if (ex == lastRank && piece == V.PAWN) {
+ // Promotion by push or pull
+ V.PawnSpecs.promotions.forEach(p => {
+ let move = super.getBasicMove([sx, sy], [ex, ey], { c: color, p: p });
+ moves.push(move);
+ });
+ } else moves.push(super.getBasicMove([sx, sy], [ex, ey]));
+ const actionType =
+ (
+ Math.abs(pa[0] - sx) < Math.abs(pa[0] - ex) ||
+ Math.abs(pa[1] - sy) < Math.abs(pa[1] - ey)
+ )
+ ? "push"
+ : "pull";
+ moves.forEach(m => m.action = [{ by: pa, type: actionType }]);
+ return moves;
+ }
+
+ // TODO: if type is given, consider only actions of this type
+ getPactions(sq, color, type) {