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