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