Fix initial knights+camels position in Wildebeest
[vchess.git] / public / javascripts / variants / Crazyhouse.js
1 class CrazyhouseRules extends ChessRules
2 {
3 initVariables(fen)
4 {
5 super.initVariables(fen);
6 // Also init reserves (used by the interface to show landing pieces)
7 const V = VariantRules;
8 this.reserve =
9 {
10 "w":
11 {
12 [V.PAWN]: 0,
13 [V.ROOK]: 0,
14 [V.KNIGHT]: 0,
15 [V.BISHOP]: 0,
16 [V.QUEEN]: 0,
17 },
18 "b":
19 {
20 [V.PAWN]: 0,
21 [V.ROOK]: 0,
22 [V.KNIGHT]: 0,
23 [V.BISHOP]: 0,
24 [V.QUEEN]: 0,
25 }
26 };
27 const [sizeX,sizeY] = VariantRules.size;
28 this.promoted = doubleArray(sizeX, sizeY, false);
29 // May be a continuation: adjust numbers of pieces in reserve + promoted pieces
30 this.moves.forEach(m => { this.updateVariables(m); });
31 }
32
33 getColor(i,j)
34 {
35 const sizeX = VariantRules.size[0];
36 if (i >= sizeX)
37 return (i==sizeX ? "w" : "b");
38 return this.board[i][j].charAt(0);
39 }
40 getPiece(i,j)
41 {
42 const sizeX = VariantRules.size[0];
43 if (i >= sizeX)
44 return VariantRules.RESERVE_PIECES[j];
45 return this.board[i][j].charAt(1);
46 }
47
48 // Used by the interface:
49 getReservePpath(color, index)
50 {
51 return color + VariantRules.RESERVE_PIECES[index];
52 }
53
54 // Put an ordering on reserve pieces
55 static get RESERVE_PIECES() {
56 const V = VariantRules;
57 return [V.PAWN,V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
58 }
59
60 getReserveMoves([x,y])
61 {
62 const color = this.turn;
63 const p = VariantRules.RESERVE_PIECES[y];
64 if (this.reserve[color][p] == 0)
65 return [];
66 let moves = [];
67 const [sizeX,sizeY] = VariantRules.size;
68 const pawnShift = (p==VariantRules.PAWN ? 1 : 0);
69 for (let i=pawnShift; i<sizeX-pawnShift; i++)
70 {
71 for (let j=0; j<sizeY; j++)
72 {
73 if (this.board[i][j] == VariantRules.EMPTY)
74 {
75 let mv = new Move({
76 appear: [
77 new PiPo({
78 x: i,
79 y: j,
80 c: color,
81 p: p
82 })
83 ],
84 vanish: [],
85 start: {x:x, y:y}, //a bit artificial...
86 end: {x:i, y:j}
87 });
88 moves.push(mv);
89 }
90 }
91 }
92 return moves;
93 }
94
95 getPotentialMovesFrom([x,y])
96 {
97 const sizeX = VariantRules.size[0];
98 if (x >= sizeX)
99 {
100 // Reserves, outside of board: x == sizeX
101 return this.getReserveMoves([x,y]);
102 }
103 // Standard moves
104 return super.getPotentialMovesFrom([x,y]);
105 }
106
107 getAllValidMoves()
108 {
109 let moves = super.getAllValidMoves();
110 const color = this.turn;
111 const sizeX = VariantRules.size[0];
112 for (let i=0; i<VariantRules.RESERVE_PIECES.length; i++)
113 moves = moves.concat(this.getReserveMoves([sizeX+(color=="w"?0:1),i]));
114 return this.filterValid(moves);
115 }
116
117 atLeastOneMove()
118 {
119 if (!super.atLeastOneMove())
120 {
121 const sizeX = VariantRules.size[0];
122 // Scan for reserve moves
123 for (let i=0; i<VariantRules.RESERVE_PIECES.length; i++)
124 {
125 let moves = this.filterValid(this.getReserveMoves([sizeX,i]));
126 if (moves.length > 0)
127 return true;
128 }
129 return false;
130 }
131 return true;
132 }
133
134 updateVariables(move)
135 {
136 super.updateVariables(move);
137 if (move.vanish.length == 2 && move.appear.length == 2)
138 return; //skip castle
139 const color = this.turn;
140 const V = VariantRules;
141 if (move.vanish.length == 0)
142 {
143 this.reserve[color][move.appear[0].p]--;
144 return;
145 }
146 move.movePromoted = this.promoted[move.start.x][move.start.y];
147 move.capturePromoted = this.promoted[move.end.x][move.end.y]
148 this.promoted[move.start.x][move.start.y] = false;
149 this.promoted[move.end.x][move.end.y] = move.movePromoted
150 || (move.vanish[0].p == V.PAWN && move.appear[0].p != V.PAWN);
151 if (move.capturePromoted)
152 this.reserve[color][VariantRules.PAWN]++;
153 else if (move.vanish.length == 2)
154 this.reserve[color][move.vanish[1].p]++;
155 }
156
157 unupdateVariables(move)
158 {
159 super.unupdateVariables(move);
160 if (move.vanish.length == 2 && move.appear.length == 2)
161 return;
162 const color = this.turn;
163 const V = VariantRules;
164 if (move.vanish.length == 0)
165 {
166 this.reserve[color][move.appear[0].p]++;
167 return;
168 }
169 if (move.movePromoted)
170 this.promoted[move.start.x][move.start.y] = true;
171 this.promoted[move.end.x][move.end.y] = move.capturePromoted;
172 if (move.capturePromoted)
173 this.reserve[color][VariantRules.PAWN]--;
174 else if (move.vanish.length == 2)
175 this.reserve[color][move.vanish[1].p]--;
176 }
177
178 static get SEARCH_DEPTH() { return 2; } //high branching factor
179
180 evalPosition()
181 {
182 let evaluation = super.evalPosition();
183 // Add reserves:
184 for (let i=0; i<VariantRules.RESERVE_PIECES.length; i++)
185 {
186 const p = VariantRules.RESERVE_PIECES[i];
187 evaluation += this.reserve["w"][p] * VariantRules.VALUES[p];
188 evaluation -= this.reserve["b"][p] * VariantRules.VALUES[p];
189 }
190 return evaluation;
191 }
192
193 getNotation(move)
194 {
195 if (move.vanish.length > 0)
196 return super.getNotation(move);
197 // Rebirth:
198 const piece =
199 (move.appear[0].p != VariantRules.PAWN ? move.appear[0].p.toUpperCase() : "");
200 const finalSquare =
201 String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
202 return piece + "@" + finalSquare;
203 }
204
205 getLongNotation(move)
206 {
207 if (move.vanish.length > 0)
208 return super.getLongNotation(move);
209 const finalSquare =
210 String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
211 return "@" + finalSquare;
212 }
213 }