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