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