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