Improve style on variant page; TODO: problems, Crazyhouse
[vchess.git] / public / javascripts / variants / Crazyhouse.js
CommitLineData
a6abf094
BA
1class CrazyhouseRules extends ChessRules
2{
2d7194bd 3 static IsGoodFen(fen)
a6abf094 4 {
2d7194bd
BA
5 if (!ChessRules.IsGoodFen(fen))
6 return false;
7 const fenParsed = V.ParseFen(fen);
8 // 5) Check reserves
9 if (!fenParsed.reserve || !fenParsed.reserve.match(/^[0-9]{10,10}$/))
10 return false;
11 // 6) Check promoted array
12 if (!fenParsed.promoted)
13 return false;
14 fenpromoted = fenParsed.promoted;
15 if (fenpromoted == "-")
16 return true; //no promoted piece on board
17 const squares = fenpromoted.split(",");
18 for (let square of squares)
19 {
20 const c = V.SquareToCoords(square);
21 if (c.y < 0 || c.y > V.size.y || isNaN(c.x) || c.x < 0 || c.x > V.size.x)
22 return false;
23 }
24 return true;
25 }
26
fb6ceeff
BA
27 static ParseFen(fen)
28 {
29 const fenParts = fen.split(" ");
30 return Object.assign(
31 ChessRules.ParseFen(fen),
32 {
33 reserve: fenParts[4],
34 promoted: fenParts[5],
35 }
36 );
37 }
38
2d7194bd
BA
39 static GenRandInitFen()
40 {
fb6ceeff 41 return ChessRules.GenRandInitFen() + " 0000000000 -";
2d7194bd
BA
42 }
43
44 getFen()
45 {
46 return super.getFen() + " " + this.getReserveFen() + " " + this.getPromotedFen();
47 }
48
49 getReserveFen()
50 {
51 let counts = _.map(_.range(10), 0);
52 for (let i=0; i<V.PIECES.length; i++)
53 {
54 counts[i] = this.reserve["w"][V.PIECES[i]];
55 counts[5+i] = this.reserve["b"][V.PIECES[i]];
56 }
57 return counts.join("");
58 }
59
60 getPromotedFen()
61 {
62 let res = "";
63 for (let i=0; i<V.size.x; i++)
64 {
65 for (let j=0; j<V.size.y; j++)
66 {
67 if (this.promoted[i][j])
68 res += V.CoordsToSquare({x:i,y:j});
69 }
70 }
71 if (res.length > 0)
72 res = res.slice(0,-1); //remove last comma
fb6ceeff
BA
73 else
74 res = "-";
2d7194bd
BA
75 return res;
76 }
77
78 setOtherVariables(fen)
79 {
80 super.setOtherVariables(fen);
81 const fenParsed = V.ParseFen(fen);
82 // Also init reserves (used by the interface to show landable pieces)
a6abf094
BA
83 this.reserve =
84 {
85 "w":
86 {
2d7194bd
BA
87 [V.PAWN]: parseInt(fenParsed.reserve[0]),
88 [V.ROOK]: parseInt(fenParsed.reserve[1]),
89 [V.KNIGHT]: parseInt(fenParsed.reserve[2]),
90 [V.BISHOP]: parseInt(fenParsed.reserve[3]),
91 [V.QUEEN]: parseInt(fenParsed.reserve[4]),
a6abf094
BA
92 },
93 "b":
94 {
2d7194bd
BA
95 [V.PAWN]: parseInt(fenParsed.reserve[5]),
96 [V.ROOK]: parseInt(fenParsed.reserve[6]),
97 [V.KNIGHT]: parseInt(fenParsed.reserve[7]),
98 [V.BISHOP]: parseInt(fenParsed.reserve[8]),
99 [V.QUEEN]: parseInt(fenParsed.reserve[9]),
a6abf094
BA
100 }
101 };
0b7d99ec 102 this.promoted = doubleArray(V.size.x, V.size.y, false);
fb6ceeff 103 if (fenParsed.promoted != "-")
2d7194bd 104 {
fb6ceeff
BA
105 for (let square of fenParsed.promoted.split(","))
106 {
107 const [x,y] = V.SquareToCoords(square);
108 promoted[x][y] = true;
109 }
2d7194bd 110 }
5c42c64e
BA
111 }
112
113 getColor(i,j)
114 {
0b7d99ec
BA
115 if (i >= V.size.x)
116 return (i==V.size.x ? "w" : "b");
5c42c64e
BA
117 return this.board[i][j].charAt(0);
118 }
2d7194bd 119
5c42c64e
BA
120 getPiece(i,j)
121 {
0b7d99ec
BA
122 if (i >= V.size.x)
123 return V.RESERVE_PIECES[j];
5c42c64e 124 return this.board[i][j].charAt(1);
a6abf094
BA
125 }
126
127 // Used by the interface:
1221ac47 128 getReservePpath(color, index)
a6abf094 129 {
0b7d99ec 130 return color + V.RESERVE_PIECES[index];
a6abf094
BA
131 }
132
92342261 133 // Ordering on reserve pieces
2d7194bd
BA
134 static get RESERVE_PIECES()
135 {
1221ac47
BA
136 return [V.PAWN,V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
137 }
138
139 getReserveMoves([x,y])
a6abf094 140 {
a6abf094 141 const color = this.turn;
0b7d99ec 142 const p = V.RESERVE_PIECES[y];
1221ac47
BA
143 if (this.reserve[color][p] == 0)
144 return [];
145 let moves = [];
0b7d99ec
BA
146 const pawnShift = (p==V.PAWN ? 1 : 0);
147 for (let i=pawnShift; i<V.size.x-pawnShift; i++)
1221ac47 148 {
0b7d99ec 149 for (let j=0; j<V.size.y; j++)
1221ac47 150 {
0b7d99ec 151 if (this.board[i][j] == V.EMPTY)
1221ac47
BA
152 {
153 let mv = new Move({
154 appear: [
155 new PiPo({
156 x: i,
157 y: j,
158 c: color,
159 p: p
160 })
5c42c64e
BA
161 ],
162 vanish: [],
6752407b 163 start: {x:x, y:y}, //a bit artificial...
5c42c64e 164 end: {x:i, y:j}
1221ac47
BA
165 });
166 moves.push(mv);
167 }
168 }
169 }
a6abf094
BA
170 return moves;
171 }
172
1221ac47 173 getPotentialMovesFrom([x,y])
a6abf094 174 {
0b7d99ec 175 if (x >= V.size.x)
6752407b 176 {
92342261 177 // Reserves, outside of board: x == sizeX(+1)
6752407b
BA
178 return this.getReserveMoves([x,y]);
179 }
180 // Standard moves
181 return super.getPotentialMovesFrom([x,y]);
a6abf094
BA
182 }
183
a6abf094
BA
184 getAllValidMoves()
185 {
1221ac47
BA
186 let moves = super.getAllValidMoves();
187 const color = this.turn;
0b7d99ec
BA
188 for (let i=0; i<V.RESERVE_PIECES.length; i++)
189 moves = moves.concat(this.getReserveMoves([V.size.x+(color=="w"?0:1),i]));
1221ac47 190 return this.filterValid(moves);
a6abf094
BA
191 }
192
a6abf094
BA
193 atLeastOneMove()
194 {
1221ac47
BA
195 if (!super.atLeastOneMove())
196 {
0b7d99ec
BA
197 const color = this.turn;
198 // Search one reserve move
199 for (let i=0; i<V.RESERVE_PIECES.length; i++)
1221ac47 200 {
0b7d99ec
BA
201 let moves = this.filterValid(
202 this.getReserveMoves([V.size.x+(this.turn=="w"?0:1), i]) );
1221ac47
BA
203 if (moves.length > 0)
204 return true;
205 }
206 return false;
207 }
208 return true;
a6abf094
BA
209 }
210
a6abf094
BA
211 updateVariables(move)
212 {
1221ac47 213 super.updateVariables(move);
6752407b
BA
214 if (move.vanish.length == 2 && move.appear.length == 2)
215 return; //skip castle
1221ac47 216 const color = this.turn;
6752407b 217 if (move.vanish.length == 0)
6752407b 218 {
8a60cacd
BA
219 this.reserve[color][move.appear[0].p]--;
220 return;
6752407b 221 }
8a60cacd
BA
222 move.movePromoted = this.promoted[move.start.x][move.start.y];
223 move.capturePromoted = this.promoted[move.end.x][move.end.y]
224 this.promoted[move.start.x][move.start.y] = false;
225 this.promoted[move.end.x][move.end.y] = move.movePromoted
226 || (move.vanish[0].p == V.PAWN && move.appear[0].p != V.PAWN);
227 if (move.capturePromoted)
0b7d99ec 228 this.reserve[color][V.PAWN]++;
8a60cacd
BA
229 else if (move.vanish.length == 2)
230 this.reserve[color][move.vanish[1].p]++;
a6abf094 231 }
1221ac47 232
a6abf094
BA
233 unupdateVariables(move)
234 {
1221ac47 235 super.unupdateVariables(move);
8a60cacd
BA
236 if (move.vanish.length == 2 && move.appear.length == 2)
237 return;
1221ac47 238 const color = this.turn;
6752407b 239 if (move.vanish.length == 0)
6752407b 240 {
8a60cacd
BA
241 this.reserve[color][move.appear[0].p]++;
242 return;
6752407b 243 }
8a60cacd
BA
244 if (move.movePromoted)
245 this.promoted[move.start.x][move.start.y] = true;
246 this.promoted[move.end.x][move.end.y] = move.capturePromoted;
247 if (move.capturePromoted)
0b7d99ec 248 this.reserve[color][V.PAWN]--;
8a60cacd
BA
249 else if (move.vanish.length == 2)
250 this.reserve[color][move.vanish[1].p]--;
a6abf094
BA
251 }
252
253 static get SEARCH_DEPTH() { return 2; } //high branching factor
254
6752407b
BA
255 evalPosition()
256 {
257 let evaluation = super.evalPosition();
258 // Add reserves:
0b7d99ec 259 for (let i=0; i<V.RESERVE_PIECES.length; i++)
6752407b 260 {
0b7d99ec
BA
261 const p = V.RESERVE_PIECES[i];
262 evaluation += this.reserve["w"][p] * V.VALUES[p];
263 evaluation -= this.reserve["b"][p] * V.VALUES[p];
6752407b
BA
264 }
265 return evaluation;
266 }
267
a6abf094
BA
268 getNotation(move)
269 {
270 if (move.vanish.length > 0)
271 return super.getNotation(move);
272 // Rebirth:
273 const piece =
0b7d99ec 274 (move.appear[0].p != V.PAWN ? move.appear[0].p.toUpperCase() : "");
2d7194bd 275 return piece + "@" + V.CoordsToSquare(move.end);
a6abf094 276 }
6752407b
BA
277
278 getLongNotation(move)
279 {
280 if (move.vanish.length > 0)
281 return super.getLongNotation(move);
2d7194bd 282 return "@" + V.CoordsToSquare(move.end);
6752407b 283 }
a6abf094 284}
643479f8
BA
285
286const VariantRules = CrazyhouseRules;