Saving state - unstable
[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 var moves = [];
14 let [sizeX,sizeY] = VariantRules.size;
15 outerLoop:
16 for (var loop=0; loop<steps.length; loop++)
17 {
18 var step = steps[loop];
19 var i = x + step[0];
20 var 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 var V = VariantRules;
42 var steps = asA != V.PAWN
43 ? V.steps[asA]
44 : color=='w' ? [[-1,-1],[-1,1]] : [[1,-1],[1,1]];
45 var oneStep = (asA==V.KNIGHT || asA==V.PAWN); //we don't capture king
46 let [sizeX,sizeY] = V.size;
47 let lastRank = (color == 'w' ? 0 : sizeY-1);
48 let promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
49 outerLoop:
50 for (var loop=0; loop<steps.length; loop++)
51 {
52 var step = steps[loop];
53 var i = x + step[0];
54 var j = y + step[1];
55 while (i>=0 && i<sizeX && j>=0 && j<sizeY
56 && this.board[i][j] == V.EMPTY)
57 {
58 if (oneStep)
59 continue outerLoop;
60 i += step[0];
61 j += step[1];
62 }
63 if (i>=0 && i<sizeX && j>=0 && j<sizeY &&
64 this.getColor(i,j) == this.getOppCol(color) && this.getPiece(i,j) == asA)
65 {
66 // eat!
67 if (this.getPiece(x,y) == V.PAWN && i == lastRank)
68 {
69 // Special case of promotion:
70 promotionPieces.forEach(p => {
71 moves.push(this.getBasicMove([x,y], [i,j], {c:color,p:p}));
72 });
73 }
74 else
75 {
76 // All other cases
77 moves.push(this.getBasicMove([x,y], [i,j]));
78 }
79 }
80 }
81 return moves;
82 }
83
84 // Find possible captures from a square: look in every direction!
85 findCaptures(sq)
86 {
87 var moves = [];
88
89 // PAWN
90 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.PAWN));
91
92 // ROOK
93 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.ROOK));
94
95 // KNIGHT
96 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.KNIGHT));
97
98 // BISHOP
99 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.BISHOP));
100
101 // QUEEN
102 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.QUEEN));
103
104 return moves;
105 }
106
107 getPotentialPawnMoves([x,y])
108 {
109 const color = this.getColor(x,y);
110 var moves = [];
111 var V = VariantRules;
112 let [sizeX,sizeY] = VariantRules.size;
113 let shift = (color == 'w' ? -1 : 1);
114 let startRank = (color == 'w' ? sizeY-2 : 1);
115 let firstRank = (color == 'w' ? sizeY-1 : 0);
116 let lastRank = (color == "w" ? 0 : sizeY-1);
117
118 if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank)
119 {
120 // Normal moves
121 if (this.board[x+shift][y] == V.EMPTY)
122 {
123 moves.push(this.getBasicMove([x,y], [x+shift,y]));
124 if ([startRank,firstRank].includes(x) && this.board[x+2*shift][y] == V.EMPTY)
125 {
126 //two squares jump
127 moves.push(this.getBasicMove([x,y], [x+2*shift,y]));
128 }
129 }
130 }
131
132 if (x+shift == lastRank)
133 {
134 // Promotion
135 let promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
136 promotionPieces.forEach(p => {
137 // Normal move
138 if (this.board[x+shift][y] == V.EMPTY)
139 moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p}));
140 });
141 }
142
143 // No en passant here
144
145 // Add "zen" captures
146 Array.prototype.push.apply(moves, this.findCaptures([x,y]));
147
148 return moves;
149 }
150
151 getPotentialRookMoves(sq)
152 {
153 let noCaptures = this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.ROOK]);
154 let captures = this.findCaptures(sq);
155 return noCaptures.concat(captures);
156 }
157
158 getPotentialKnightMoves(sq)
159 {
160 let noCaptures = this.getSlideNJumpMoves(sq, 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 let noCaptures = this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.QUEEN]);
175 let captures = this.findCaptures(sq);
176 return noCaptures.concat(captures);
177 }
178
179 getPotentialKingMoves(sq)
180 {
181 // Initialize with normal moves
182 let noCaptures = this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.QUEEN], "oneStep");
183 let captures = this.findCaptures(sq);
184 return noCaptures.concat(captures).concat(this.getCastleMoves(sq));
185 }
186
187 getNotation(move)
188 {
189 // Recognize special moves first
190 if (move.appear.length == 2)
191 {
192 // castle
193 if (move.end.y < move.start.y)
194 return "0-0-0";
195 else
196 return "0-0";
197 }
198
199 // Translate initial square (because pieces may fly unusually in this variant!)
200 let initialSquare =
201 String.fromCharCode(97 + move.start.y) + (VariantRules.size[0]-move.start.x);
202
203 // Translate final square
204 let finalSquare =
205 String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
206
207 let notation = "";
208 let piece = this.getPiece(move.start.x, move.start.y);
209 if (piece == VariantRules.PAWN)
210 {
211 // pawn move (TODO: enPassant indication)
212 if (move.vanish.length > 1)
213 {
214 // capture
215 notation = initialSquare + "x" + finalSquare;
216 }
217 else //no capture
218 notation = finalSquare;
219 if (piece != move.appear[0].p) //promotion
220 notation += "=" + move.appear[0].p.toUpperCase();
221 }
222
223 else
224 {
225 // Piece movement
226 notation = piece.toUpperCase();
227 if (move.vanish.length > 1)
228 notation += initialSquare + "x";
229 notation += finalSquare;
230 }
231 return notation;
232 }
233
234 static get VALUES() { //TODO: experimental
235 return {
236 'p': 1,
237 'r': 3,
238 'n': 2,
239 'b': 2,
240 'q': 5,
241 'k': 1000
242 }
243 }
244 }