Fix en-passant for Wildebeest, draft Benedict variant
[vchess.git] / client / src / variants / Zen.js
1 import { ChessRules } from "@/base_rules";
2
3 export const VariantRules = class ZenRules extends ChessRules {
4 // NOTE: enPassant, if enabled, would need to redefine carefully getEpSquare
5 static get HasEnpassant() {
6 return false;
7 }
8
9 // TODO(?): some duplicated code in 2 next functions
10 getSlideNJumpMoves([x, y], steps, oneStep) {
11 let moves = [];
12 outerLoop: for (let loop = 0; loop < steps.length; loop++) {
13 const step = steps[loop];
14 let i = x + step[0];
15 let j = y + step[1];
16 while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
17 moves.push(this.getBasicMove([x, y], [i, j]));
18 if (oneStep) continue outerLoop;
19 i += step[0];
20 j += step[1];
21 }
22 // No capture check: handled elsewhere (next method)
23 }
24 return moves;
25 }
26
27 // follow steps from x,y until something is met.
28 // if met piece is opponent and same movement (asA): eat it!
29 findCaptures_aux([x, y], asA) {
30 const color = this.getColor(x, y);
31 let moves = [];
32 const steps =
33 asA != V.PAWN
34 ? asA == V.QUEEN
35 ? V.steps[V.ROOK].concat(V.steps[V.BISHOP])
36 : V.steps[asA]
37 : color == "w"
38 ? [
39 [-1, -1],
40 [-1, 1]
41 ]
42 : [
43 [1, -1],
44 [1, 1]
45 ];
46 const oneStep = [V.KNIGHT,V.PAWN].includes(asA); //we don't capture king
47 const lastRank = color == "w" ? 0 : V.size.x - 1;
48 const promotionPieces = [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN];
49 outerLoop: for (let loop = 0; loop < steps.length; loop++) {
50 const step = steps[loop];
51 let i = x + step[0];
52 let j = y + step[1];
53 while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
54 if (oneStep) continue outerLoop;
55 i += step[0];
56 j += step[1];
57 }
58 if (
59 V.OnBoard(i, j) &&
60 this.getColor(i, j) == V.GetOppCol(color) &&
61 this.getPiece(i, j) == asA
62 ) {
63 // eat!
64 if (this.getPiece(x, y) == V.PAWN && i == lastRank) {
65 // Special case of promotion:
66 promotionPieces.forEach(p => {
67 moves.push(this.getBasicMove([x, y], [i, j], { c: color, p: p }));
68 });
69 } else {
70 // All other cases
71 moves.push(this.getBasicMove([x, y], [i, j]));
72 }
73 }
74 }
75 return moves;
76 }
77
78 // Find possible captures from a square: look in every direction!
79 findCaptures(sq) {
80 let moves = [];
81
82 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.PAWN));
83 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.ROOK));
84 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.KNIGHT));
85 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.BISHOP));
86 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.QUEEN));
87
88 return moves;
89 }
90
91 getPotentialPawnMoves([x, y]) {
92 const color = this.getColor(x, y);
93 let moves = [];
94 const sizeY = V.size.y;
95 const shift = color == "w" ? -1 : 1;
96 const startRank = color == "w" ? sizeY - 2 : 1;
97 const firstRank = color == "w" ? sizeY - 1 : 0;
98 const lastRank = color == "w" ? 0 : sizeY - 1;
99
100 if (x + shift != lastRank) {
101 // Normal moves
102 if (this.board[x + shift][y] == V.EMPTY) {
103 moves.push(this.getBasicMove([x, y], [x + shift, y]));
104 if (
105 [startRank, firstRank].includes(x) &&
106 this.board[x + 2 * shift][y] == V.EMPTY
107 ) {
108 // Two squares jump
109 moves.push(this.getBasicMove([x, y], [x + 2 * shift, y]));
110 }
111 }
112 }
113 else {
114 // Promotion
115 let promotionPieces = [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN];
116 promotionPieces.forEach(p => {
117 // Normal move
118 if (this.board[x + shift][y] == V.EMPTY)
119 moves.push(
120 this.getBasicMove([x, y], [x + shift, y], { c: color, p: p })
121 );
122 });
123 }
124
125 // No en passant here
126
127 // Add "zen" captures
128 Array.prototype.push.apply(moves, this.findCaptures([x, y]));
129
130 return moves;
131 }
132
133 getPotentialRookMoves(sq) {
134 let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.ROOK]);
135 let captures = this.findCaptures(sq);
136 return noCaptures.concat(captures);
137 }
138
139 getPotentialKnightMoves(sq) {
140 let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep");
141 let captures = this.findCaptures(sq);
142 return noCaptures.concat(captures);
143 }
144
145 getPotentialBishopMoves(sq) {
146 let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]);
147 let captures = this.findCaptures(sq);
148 return noCaptures.concat(captures);
149 }
150
151 getPotentialQueenMoves(sq) {
152 let noCaptures = this.getSlideNJumpMoves(
153 sq,
154 V.steps[V.ROOK].concat(V.steps[V.BISHOP])
155 );
156 let captures = this.findCaptures(sq);
157 return noCaptures.concat(captures);
158 }
159
160 getPotentialKingMoves(sq) {
161 // Initialize with normal moves
162 let noCaptures = this.getSlideNJumpMoves(
163 sq,
164 V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
165 "oneStep"
166 );
167 let captures = this.findCaptures(sq);
168 return noCaptures.concat(captures).concat(this.getCastleMoves(sq));
169 }
170
171 getNotation(move) {
172 // Recognize special moves first
173 if (move.appear.length == 2) {
174 // castle
175 if (move.end.y < move.start.y) return "0-0-0";
176 return "0-0";
177 }
178
179 // Translate initial square (because pieces may fly unusually in this variant!)
180 const initialSquare = V.CoordsToSquare(move.start);
181
182 // Translate final square
183 const finalSquare = V.CoordsToSquare(move.end);
184
185 let notation = "";
186 const piece = this.getPiece(move.start.x, move.start.y);
187 if (piece == V.PAWN) {
188 // pawn move (TODO: enPassant indication)
189 if (move.vanish.length > 1) {
190 // capture
191 notation = initialSquare + "x" + finalSquare;
192 } //no capture
193 else notation = finalSquare;
194 if (piece != move.appear[0].p)
195 //promotion
196 notation += "=" + move.appear[0].p.toUpperCase();
197 } else {
198 // Piece movement
199 notation = piece.toUpperCase();
200 if (move.vanish.length > 1) notation += initialSquare + "x";
201 notation += finalSquare;
202 }
203 return notation;
204 }
205
206 static get VALUES() {
207 return {
208 p: 1,
209 r: 3,
210 n: 2,
211 b: 2,
212 q: 5,
213 k: 1000
214 };
215 }
216 };