Experimental board size auto-adjust
[vchess.git] / client / src / variants / Berolina.js
CommitLineData
0c3fe8a6
BA
1import { ChessRules } from "@/base_rules";
2
32f6285e 3export class BerolinaRules extends ChessRules {
7e8a7ea1 4
dac39588 5 // En-passant after 2-sq jump
6808d7a1
BA
6 getEpSquare(moveOrSquare) {
7 if (!moveOrSquare) return undefined;
8 if (typeof moveOrSquare === "string") {
dac39588 9 const square = moveOrSquare;
6808d7a1 10 if (square == "-") return undefined;
dac39588
BA
11 // Enemy pawn initial column must be given too:
12 let res = [];
13 const epParts = square.split(",");
14 res.push(V.SquareToCoords(epParts[0]));
15 res.push(V.ColumnToCoord(epParts[1]));
16 return res;
17 }
18 // Argument is a move:
19 const move = moveOrSquare;
6808d7a1
BA
20 const [sx, ex, sy] = [move.start.x, move.end.x, move.start.y];
21 if (this.getPiece(sx, sy) == V.PAWN && Math.abs(sx - ex) == 2) {
8d1fcc37
BA
22 return [
23 {
24 x: (ex + sx) / 2,
25 y: (move.end.y + sy) / 2
26 },
27 // The arrival column must be remembered, because
28 // potentially two pawns could be candidates to be captured:
29 // one on our left, and one on our right.
30 move.end.y
31 ];
dac39588
BA
32 }
33 return undefined; //default
34 }
375ecdd1 35
8d1fcc37
BA
36 static IsGoodEnpassant(enpassant) {
37 if (enpassant != "-") {
38 const epParts = enpassant.split(",");
39 const epSq = V.SquareToCoords(epParts[0]);
40 if (isNaN(epSq.x) || isNaN(epSq.y) || !V.OnBoard(epSq)) return false;
41 const arrCol = V.ColumnToCoord(epParts[1]);
42 if (isNaN(arrCol) || arrCol < 0 || arrCol >= V.size.y) return false;
43 }
44 return true;
45 }
46
47 getEnpassantFen() {
48 const L = this.epSquares.length;
49 if (!this.epSquares[L - 1]) return "-"; //no en-passant
50 return (
51 V.CoordsToSquare(this.epSquares[L - 1][0]) +
52 "," +
53 V.CoordToColumn(this.epSquares[L - 1][1])
54 );
55 }
56
f52671e5
BA
57 getEnpassantCaptures([x, y], shift) {
58 const Lep = this.epSquares.length;
59 const epSquare = this.epSquares[Lep - 1]; //always at least one element
60 if (
61 !!epSquare &&
62 epSquare[0].x == x + shift &&
63 epSquare[0].y == y
64 ) {
65 let enpassantMove = this.getBasicMove([x, y], [x + shift, y]);
66 enpassantMove.vanish.push({
67 x: x,
68 y: epSquare[1],
69 p: "p",
70 c: this.getColor(x, epSquare[1])
71 });
72 return [enpassantMove];
73 }
74 return [];
75 }
76
dac39588 77 // Special pawns movements
6808d7a1 78 getPotentialPawnMoves([x, y]) {
dac39588
BA
79 const color = this.turn;
80 let moves = [];
6808d7a1
BA
81 const [sizeX, sizeY] = [V.size.x, V.size.y];
82 const shiftX = color == "w" ? -1 : 1;
83 const startRank = color == "w" ? sizeX - 2 : 1;
84 const lastRank = color == "w" ? 0 : sizeX - 1;
85 const finalPieces =
2c5d7b20
BA
86 x + shiftX == lastRank
87 ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]
88 : [V.PAWN];
375ecdd1 89
dac39588 90 // One square diagonally
6808d7a1
BA
91 for (let shiftY of [-1, 1]) {
92 if (this.board[x + shiftX][y + shiftY] == V.EMPTY) {
93 for (let piece of finalPieces) {
94 moves.push(
95 this.getBasicMove([x, y], [x + shiftX, y + shiftY], {
96 c: color,
97 p: piece
98 })
99 );
dac39588 100 }
6808d7a1 101 if (
32f6285e 102 V.PawnSpecs.twoSquares &&
6808d7a1
BA
103 x == startRank &&
104 y + 2 * shiftY >= 0 &&
105 y + 2 * shiftY < sizeY &&
106 this.board[x + 2 * shiftX][y + 2 * shiftY] == V.EMPTY
107 ) {
dac39588 108 // Two squares jump
6808d7a1
BA
109 moves.push(
110 this.getBasicMove([x, y], [x + 2 * shiftX, y + 2 * shiftY])
111 );
dac39588
BA
112 }
113 }
114 }
115 // Capture
6808d7a1
BA
116 if (
117 this.board[x + shiftX][y] != V.EMPTY &&
118 this.canTake([x, y], [x + shiftX, y])
119 ) {
6e47d367 120 for (let piece of finalPieces) {
6808d7a1
BA
121 moves.push(
122 this.getBasicMove([x, y], [x + shiftX, y], { c: color, p: piece })
123 );
6e47d367 124 }
dac39588 125 }
375ecdd1 126
32f6285e 127 // Next condition so that other variants could inherit from this class
f52671e5
BA
128 if (V.HasEnpassant) {
129 // NOTE: backward en-passant captures are not considered
130 // because no rules define them (for now).
131 Array.prototype.push.apply(
132 moves,
133 this.getEnpassantCaptures([x, y], shiftX)
134 );
dac39588 135 }
375ecdd1 136
dac39588
BA
137 return moves;
138 }
f6dbe8e3 139
68e19a44
BA
140 isAttackedByPawn([x, y], color) {
141 let pawnShift = (color == "w" ? 1 : -1);
59e74176
BA
142 return (
143 x + pawnShift >= 0 && x + pawnShift < V.size.x &&
144 this.getPiece(x + pawnShift, y) == V.PAWN &&
145 this.getColor(x + pawnShift, y) == color
146 );
dac39588 147 }
26c1e3bd 148
32f6285e
BA
149 static get SEARCH_DEPTH() {
150 return 2;
151 }
152
6808d7a1 153 getNotation(move) {
dac39588 154 const piece = this.getPiece(move.start.x, move.start.y);
6808d7a1 155 if (piece == V.PAWN) {
dac39588
BA
156 // Pawn move
157 const finalSquare = V.CoordsToSquare(move.end);
158 let notation = "";
6808d7a1 159 if (move.vanish.length == 2)
6e47d367 160 // Capture
dac39588 161 notation = "Px" + finalSquare;
6808d7a1 162 else {
dac39588
BA
163 // No capture: indicate the initial square for potential ambiguity
164 const startSquare = V.CoordsToSquare(move.start);
165 notation = startSquare + finalSquare;
166 }
6808d7a1 167 if (move.appear[0].p != V.PAWN)
11482348 168 // Promotion
dac39588
BA
169 notation += "=" + move.appear[0].p.toUpperCase();
170 return notation;
171 }
172 return super.getNotation(move); //all other pieces are orthodox
173 }
7e8a7ea1 174
6808d7a1 175};