+ // Complete a move with magnetic actions
+ // TODO: job is done multiple times for (normal) promotions.
+ applyMagneticLaws(move) {
+ // Exception: kings are not charged
+ if (move.appear[0].p == V.KING && move.appear.length == 1) return [move];
+ // If castling, rook is charged:
+ const aIdx = move.appear[0].p != V.KING ? 0 : 1;
+ const [x, y] = [move.appear[aIdx].x, move.appear[aIdx].y];
+ const color = this.turn;
+ const lastRank = color == "w" ? 0 : 7;
+ const standardMove = JSON.parse(JSON.stringify(move));
+ this.play(standardMove);
+ for (let step of [
+ [-1, 0],
+ [1, 0],
+ [0, -1],
+ [0, 1]
+ ]) {
+ let [i, j] = [x + step[0], y + step[1]];
+ while (V.OnBoard(i, j)) {
+ if (this.board[i][j] != V.EMPTY) {
+ // Found something. Same color or not?
+ if (this.getColor(i, j) != color) {
+ // Attraction
+ if (
+ (Math.abs(i - x) >= 2 || Math.abs(j - y) >= 2) &&
+ this.getPiece(i, j) != V.KING
+ ) {
+ move.vanish.push(
+ new PiPo({
+ p: this.getPiece(i, j),
+ c: this.getColor(i, j),
+ x: i,
+ y: j
+ })
+ );
+ move.appear.push(
+ new PiPo({
+ p: this.getPiece(i, j),
+ c: this.getColor(i, j),
+ x: x + step[0],
+ y: y + step[1]
+ })
+ );
+ }
+ } else {
+ // Repulsion
+ if (this.getPiece(i, j) != V.KING) {
+ // Push it until we meet an obstacle or edge of the board
+ let [ii, jj] = [i + step[0], j + step[1]];
+ while (V.OnBoard(ii, jj)) {
+ if (this.board[ii][jj] != V.EMPTY) break;
+ ii += step[0];
+ jj += step[1];
+ }
+ ii -= step[0];
+ jj -= step[1];
+ if (Math.abs(ii - i) >= 1 || Math.abs(jj - j) >= 1) {
+ move.vanish.push(
+ new PiPo({
+ p: this.getPiece(i, j),
+ c: this.getColor(i, j),
+ x: i,
+ y: j
+ })
+ );
+ move.appear.push(
+ new PiPo({
+ p: this.getPiece(i, j),
+ c: this.getColor(i, j),
+ x: ii,
+ y: jj
+ })
+ );
+ }
+ }
+ }
+ break;
+ }
+ i += step[0];
+ j += step[1];
+ }
+ }
+ this.undo(standardMove);
+ let moves = [];
+ // Scan move for pawn (max 1) on 8th rank
+ for (let i = 1; i < move.appear.length; i++) {
+ if (
+ move.appear[i].p == V.PAWN &&
+ move.appear[i].c == color &&
+ move.appear[i].x == lastRank
+ ) {
+ move.appear[i].p = V.ROOK;
+ moves.push(move);
+ for (let piece of [V.KNIGHT, V.BISHOP, V.QUEEN]) {
+ let cmove = JSON.parse(JSON.stringify(move));
+ cmove.appear[i].p = piece;
+ moves.push(cmove);
+ }
+ // Swap appear[i] and appear[0] for moves presentation
+ // (TODO: this is awkward)
+ moves.forEach(m => {
+ let tmp = m.appear[0];
+ m.appear[0] = m.appear[i];
+ m.appear[i] = tmp;
+ });
+ break;
+ }
+ }
+ if (moves.length == 0)
+ //no pawn on 8th rank
+ moves.push(move);
+ return moves;
+ }