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