5f8d9c093d4adb52a68fbcfe41243d2bc2b9a088
[vchess.git] / client / src / variants / Berolina.js
1 import { ChessRules } from "@/base_rules";
2
3 export const VariantRules = class BerolinaRules extends ChessRules {
4 // En-passant after 2-sq jump
5 getEpSquare(moveOrSquare) {
6 if (!moveOrSquare) return undefined;
7 if (typeof moveOrSquare === "string") {
8 const square = moveOrSquare;
9 if (square == "-") return undefined;
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;
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) {
21 return {
22 x: (ex + sx) / 2,
23 y: (move.end.y + sy) / 2
24 };
25 }
26 return undefined; //default
27 }
28
29 // Special pawns movements
30 getPotentialPawnMoves([x, y]) {
31 const color = this.turn;
32 let moves = [];
33 const [sizeX, sizeY] = [V.size.x, V.size.y];
34 const shiftX = color == "w" ? -1 : 1;
35 const startRank = color == "w" ? sizeX - 2 : 1;
36 const lastRank = color == "w" ? 0 : sizeX - 1;
37 const finalPieces =
38 x + shiftX == lastRank ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN] : [V.PAWN];
39
40 // One square diagonally
41 for (let shiftY of [-1, 1]) {
42 if (this.board[x + shiftX][y + shiftY] == V.EMPTY) {
43 for (let piece of finalPieces) {
44 moves.push(
45 this.getBasicMove([x, y], [x + shiftX, y + shiftY], {
46 c: color,
47 p: piece
48 })
49 );
50 }
51 if (
52 x == startRank &&
53 y + 2 * shiftY >= 0 &&
54 y + 2 * shiftY < sizeY &&
55 this.board[x + 2 * shiftX][y + 2 * shiftY] == V.EMPTY
56 ) {
57 // Two squares jump
58 moves.push(
59 this.getBasicMove([x, y], [x + 2 * shiftX, y + 2 * shiftY])
60 );
61 }
62 }
63 }
64 // Capture
65 if (
66 this.board[x + shiftX][y] != V.EMPTY &&
67 this.canTake([x, y], [x + shiftX, y])
68 ) {
69 for (let piece of finalPieces)
70 moves.push(
71 this.getBasicMove([x, y], [x + shiftX, y], { c: color, p: piece })
72 );
73 }
74
75 // En passant
76 const Lep = this.epSquares.length;
77 const epSquare = this.epSquares[Lep - 1]; //always at least one element
78 if (
79 !!epSquare &&
80 epSquare[0].x == x + shiftX &&
81 epSquare[0].y == y &&
82 Math.abs(epSquare[1] - y) == 1
83 ) {
84 let enpassantMove = this.getBasicMove([x, y], [x + shiftX, y]);
85 enpassantMove.vanish.push({
86 x: x,
87 y: epSquare[1],
88 p: "p",
89 c: this.getColor(x, epSquare[1])
90 });
91 moves.push(enpassantMove);
92 }
93
94 return moves;
95 }
96
97 isAttackedByPawn([x, y], colors) {
98 for (let c of colors) {
99 let pawnShift = c == "w" ? 1 : -1;
100 if (x + pawnShift >= 0 && x + pawnShift < V.size.x) {
101 if (
102 this.getPiece(x + pawnShift, y) == V.PAWN &&
103 this.getColor(x + pawnShift, y) == c
104 ) {
105 return true;
106 }
107 }
108 }
109 return false;
110 }
111
112 getNotation(move) {
113 const piece = this.getPiece(move.start.x, move.start.y);
114 if (piece == V.PAWN) {
115 // Pawn move
116 const finalSquare = V.CoordsToSquare(move.end);
117 let notation = "";
118 if (move.vanish.length == 2)
119 //capture
120 notation = "Px" + finalSquare;
121 else {
122 // No capture: indicate the initial square for potential ambiguity
123 const startSquare = V.CoordsToSquare(move.start);
124 notation = startSquare + finalSquare;
125 }
126 if (move.appear[0].p != V.PAWN)
127 //promotion
128 notation += "=" + move.appear[0].p.toUpperCase();
129 return notation;
130 }
131 return super.getNotation(move); //all other pieces are orthodox
132 }
133 };