Code reorganization
[vchess.git] / client / src / variants / Zen.js
... / ...
CommitLineData
1class 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) == V.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 != 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 else //promotion
115 {
116 let promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
117 promotionPieces.forEach(p => {
118 // Normal move
119 if (this.board[x+shift][y] == V.EMPTY)
120 moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p}));
121 });
122 }
123
124 // No en passant here
125
126 // Add "zen" captures
127 Array.prototype.push.apply(moves, this.findCaptures([x,y]));
128
129 return moves;
130 }
131
132 getPotentialRookMoves(sq)
133 {
134 let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.ROOK]);
135 let captures = this.findCaptures(sq);
136 return noCaptures.concat(captures);
137 }
138
139 getPotentialKnightMoves(sq)
140 {
141 let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep");
142 let captures = this.findCaptures(sq);
143 return noCaptures.concat(captures);
144 }
145
146 getPotentialBishopMoves(sq)
147 {
148 let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]);
149 let captures = this.findCaptures(sq);
150 return noCaptures.concat(captures);
151 }
152
153 getPotentialQueenMoves(sq)
154 {
155 let noCaptures = this.getSlideNJumpMoves(
156 sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]));
157 let captures = this.findCaptures(sq);
158 return noCaptures.concat(captures);
159 }
160
161 getPotentialKingMoves(sq)
162 {
163 // Initialize with normal moves
164 let noCaptures = this.getSlideNJumpMoves(sq,
165 V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
166 let captures = this.findCaptures(sq);
167 return noCaptures.concat(captures).concat(this.getCastleMoves(sq));
168 }
169
170 getNotation(move)
171 {
172 // Recognize special moves first
173 if (move.appear.length == 2)
174 {
175 // castle
176 if (move.end.y < move.start.y)
177 return "0-0-0";
178 else
179 return "0-0";
180 }
181
182 // Translate initial square (because pieces may fly unusually in this variant!)
183 const initialSquare = V.CoordsToSquare(move.start);
184
185 // Translate final square
186 const finalSquare = V.CoordsToSquare(move.end);
187
188 let notation = "";
189 const piece = this.getPiece(move.start.x, move.start.y);
190 if (piece == V.PAWN)
191 {
192 // pawn move (TODO: enPassant indication)
193 if (move.vanish.length > 1)
194 {
195 // capture
196 notation = initialSquare + "x" + finalSquare;
197 }
198 else //no capture
199 notation = finalSquare;
200 if (piece != move.appear[0].p) //promotion
201 notation += "=" + move.appear[0].p.toUpperCase();
202 }
203
204 else
205 {
206 // Piece movement
207 notation = piece.toUpperCase();
208 if (move.vanish.length > 1)
209 notation += initialSquare + "x";
210 notation += finalSquare;
211 }
212 return notation;
213 }
214
215 static get VALUES()
216 {
217 // TODO: experimental
218 return {
219 'p': 1,
220 'r': 3,
221 'n': 2,
222 'b': 2,
223 'q': 5,
224 'k': 1000
225 }
226 }
227}