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