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