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; | |
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 | |
286 | const VariantRules = CrazyhouseRules; |