ff562d0adce48426a5d6e7769a5e4ca969ac5342
[vchess.git] / client / src / variants / Zen.js
1 import { ChessRules } from "@/base_rules";
2
3 export 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 canTake(sq1, sq2) {
92 return false; //captures handled separately
93 }
94
95 getPotentialPawnMoves([x, y]) {
96 let moves = super.getPotentialPawnMoves([x, y]);
97 // Add "zen" captures
98 Array.prototype.push.apply(moves, this.findCaptures([x, y]));
99 return moves;
100 }
101
102 getPotentialRookMoves(sq) {
103 let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.ROOK]);
104 let captures = this.findCaptures(sq);
105 return noCaptures.concat(captures);
106 }
107
108 getPotentialKnightMoves(sq) {
109 let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep");
110 let captures = this.findCaptures(sq);
111 return noCaptures.concat(captures);
112 }
113
114 getPotentialBishopMoves(sq) {
115 let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]);
116 let captures = this.findCaptures(sq);
117 return noCaptures.concat(captures);
118 }
119
120 getPotentialQueenMoves(sq) {
121 let noCaptures = this.getSlideNJumpMoves(
122 sq,
123 V.steps[V.ROOK].concat(V.steps[V.BISHOP])
124 );
125 let captures = this.findCaptures(sq);
126 return noCaptures.concat(captures);
127 }
128
129 getPotentialKingMoves(sq) {
130 // Initialize with normal moves
131 let noCaptures = this.getSlideNJumpMoves(
132 sq,
133 V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
134 "oneStep"
135 );
136 let captures = this.findCaptures(sq);
137 return noCaptures.concat(captures).concat(this.getCastleMoves(sq));
138 }
139
140 getNotation(move) {
141 // Recognize special moves first
142 if (move.appear.length == 2) {
143 // castle
144 if (move.end.y < move.start.y) return "0-0-0";
145 return "0-0";
146 }
147
148 // Translate initial square (because pieces may fly unusually!)
149 const initialSquare = V.CoordsToSquare(move.start);
150
151 // Translate final square
152 const finalSquare = V.CoordsToSquare(move.end);
153
154 let notation = "";
155 const piece = this.getPiece(move.start.x, move.start.y);
156 if (piece == V.PAWN) {
157 // pawn move (TODO: enPassant indication)
158 if (move.vanish.length > 1) {
159 // capture
160 notation = initialSquare + "x" + finalSquare;
161 } //no capture
162 else notation = finalSquare;
163 if (piece != move.appear[0].p)
164 //promotion
165 notation += "=" + move.appear[0].p.toUpperCase();
166 } else {
167 // Piece movement
168 notation = piece.toUpperCase();
169 if (move.vanish.length > 1) notation += initialSquare + "x";
170 notation += finalSquare;
171 }
172 return notation;
173 }
174
175 static get VALUES() {
176 return {
177 p: 1,
178 r: 3,
179 n: 2,
180 b: 2,
181 q: 5,
182 k: 1000
183 };
184 }
185 };