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