Commit | Line | Data |
---|---|---|
31e9e40a BA |
1 | import { ChessRules, PiPo, Move } from "@/base_rules"; |
2 | ||
241bf8f2 BA |
3 | export const VariantRules = class SuctionRules extends ChessRules { |
4 | setOtherVariables(fen) { | |
5 | super.setOtherVariables(fen); | |
6 | // Local stack of captures | |
7 | this.cmoves = []; | |
8 | const cmove = fen.split(" ")[5]; | |
9 | if (cmove == "-") this.cmoves.push(null); | |
10 | else { | |
11 | this.cmoves.push({ | |
12 | start: ChessRules.SquareToCoords(cmove.substr(0, 2)), | |
13 | end: ChessRules.SquareToCoords(cmove.substr(2)) | |
14 | }); | |
15 | } | |
16 | } | |
17 | ||
18 | static IsGoodFen(fen) { | |
19 | if (!ChessRules.IsGoodFen(fen)) return false; | |
20 | const fenParts = fen.split(" "); | |
21 | if (fenParts.length != 6) return false; | |
22 | if (fenParts[5] != "-" && !fenParts[5].match(/^([a-h][1-8]){2}$/)) | |
23 | return false; | |
24 | return true; | |
25 | } | |
26 | ||
27 | getCmove(move) { | |
28 | if (move.vanish.length == 2) | |
29 | return { start: move.start, end: move.end }; | |
30 | return null; | |
31 | } | |
32 | ||
31e9e40a BA |
33 | getBasicMove([sx, sy], [ex, ey]) { |
34 | const startColor = this.getColor(sx, sy); | |
35 | const startPiece = this.getPiece(sx, sy); | |
36 | let mv = new Move({ | |
37 | appear: [ | |
38 | new PiPo({ | |
39 | x: ex, | |
40 | y: ey, | |
41 | c: startColor, | |
42 | p: startPiece | |
43 | }) | |
44 | ], | |
45 | vanish: [ | |
46 | new PiPo({ | |
47 | x: sx, | |
48 | y: sy, | |
49 | c: startColor, | |
50 | p: startPiece | |
51 | }) | |
52 | ] | |
53 | }); | |
54 | ||
55 | if (this.board[ex][ey] != V.EMPTY) { | |
56 | const endColor = this.getColor(ex, ey); | |
57 | const endPiece = this.getPiece(ex, ey); | |
58 | mv.vanish.push( | |
59 | new PiPo({ | |
60 | x: ex, | |
61 | y: ey, | |
62 | c: endColor, | |
63 | p: endPiece | |
64 | }) | |
65 | ); | |
66 | mv.appear.push( | |
67 | new PiPo({ | |
68 | x: sx, | |
69 | y: sy, | |
70 | c: endColor, | |
71 | p: endPiece | |
72 | }) | |
73 | ); | |
74 | } | |
75 | return mv; | |
76 | } | |
77 | ||
78 | getPotentialPawnMoves([x, y]) { | |
79 | const color = this.turn; | |
80 | let moves = []; | |
81 | const [sizeX, sizeY] = [V.size.x, V.size.y]; | |
82 | const shiftX = color == "w" ? -1 : 1; | |
83 | const startRank = color == "w" ? sizeX - 2 : 1; | |
84 | const firstRank = color == "w" ? sizeX - 1 : 0; | |
85 | ||
86 | if (x + shiftX >= 0 && x + shiftX < sizeX) { | |
87 | // One square forward | |
88 | if (this.board[x + shiftX][y] == V.EMPTY) { | |
89 | moves.push( | |
90 | this.getBasicMove([x, y], [x + shiftX, y], { | |
91 | c: color, | |
92 | p: "p" | |
93 | }) | |
94 | ); | |
95 | if ( | |
96 | [startRank,firstRank].includes(x) && | |
97 | this.board[x + 2 * shiftX][y] == V.EMPTY | |
98 | ) { | |
99 | // Two squares jump | |
100 | moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y])); | |
101 | } | |
102 | } | |
103 | // Swaps | |
104 | for (let shiftY of [-1, 1]) { | |
105 | if ( | |
106 | y + shiftY >= 0 && | |
107 | y + shiftY < sizeY && | |
108 | this.board[x + shiftX][y + shiftY] != V.EMPTY && | |
109 | this.canTake([x, y], [x + shiftX, y + shiftY]) | |
110 | ) { | |
111 | moves.push( | |
112 | this.getBasicMove([x, y], [x + shiftX, y + shiftY], { | |
113 | c: color, | |
114 | p: "p" | |
115 | }) | |
116 | ); | |
117 | } | |
118 | } | |
119 | } | |
120 | ||
121 | // En passant | |
122 | const Lep = this.epSquares.length; | |
123 | const epSquare = this.epSquares[Lep - 1]; //always at least one element | |
124 | if ( | |
125 | !!epSquare && | |
126 | epSquare.x == x + shiftX && | |
127 | Math.abs(epSquare.y - y) == 1 | |
128 | ) { | |
129 | let enpassantMove = this.getBasicMove([x, y], [epSquare.x, epSquare.y]); | |
130 | const oppCol = V.GetOppCol(color); | |
131 | enpassantMove.vanish.push({ | |
132 | x: x, | |
133 | y: epSquare.y, | |
134 | p: "p", | |
135 | c: oppCol | |
136 | }); | |
137 | enpassantMove.appear.push({ | |
138 | x: x, | |
139 | y: y, | |
140 | p: "p", | |
141 | c: oppCol | |
142 | }); | |
143 | moves.push(enpassantMove); | |
144 | } | |
145 | ||
146 | return moves; | |
147 | } | |
148 | ||
149 | getPotentialKingMoves() { | |
150 | return []; | |
151 | } | |
152 | ||
241bf8f2 BA |
153 | // Does m2 un-do m1 ? (to disallow undoing captures) |
154 | oppositeMoves(m1, m2) { | |
155 | return ( | |
156 | m1 && | |
157 | m2.vanish.length == 2 && | |
158 | m1.start.x == m2.start.x && | |
159 | m1.end.x == m2.end.x && | |
160 | m1.start.y == m2.start.y && | |
161 | m1.end.y == m2.end.y | |
162 | ); | |
163 | } | |
164 | ||
165 | filterValid(moves) { | |
166 | if (moves.length == 0) return []; | |
167 | const color = this.turn; | |
168 | return moves.filter(m => { | |
169 | const L = this.cmoves.length; //at least 1: init from FEN | |
170 | return !this.oppositeMoves(this.cmoves[L - 1], m); | |
171 | }); | |
172 | } | |
173 | ||
31e9e40a BA |
174 | updateVariables(move) { |
175 | super.updateVariables(move); | |
176 | if (move.vanish.length == 2) { | |
177 | // Was opponent king swapped? | |
178 | if (move.vanish[1].p == V.KING) | |
179 | this.kingPos[this.turn] = [move.appear[1].x, move.appear[1].y]; | |
180 | } | |
181 | } | |
182 | ||
183 | unupdateVariables(move) { | |
184 | super.unupdateVariables(move); | |
185 | if (move.appear.length == 2) { | |
186 | // Was opponent king swapped? | |
187 | if (move.appear[1].p == V.KING) | |
188 | this.kingPos[move.vanish[1].c] = [move.vanish[1].x,move.vanish[1].y]; | |
189 | } | |
190 | } | |
191 | ||
7ba4a5bc | 192 | static GenRandInitFen(randomness) { |
241bf8f2 | 193 | // Add empty cmove: |
7ba4a5bc | 194 | return ChessRules.GenRandInitFen(randomness) + " -"; |
31e9e40a BA |
195 | } |
196 | ||
241bf8f2 BA |
197 | getFen() { |
198 | const L = this.cmoves.length; | |
199 | const cmoveFen = !this.cmoves[L - 1] | |
200 | ? "-" | |
201 | : ChessRules.CoordsToSquare(this.cmoves[L - 1].start) + | |
202 | ChessRules.CoordsToSquare(this.cmoves[L - 1].end); | |
203 | return super.getFen() + " " + cmoveFen; | |
204 | } | |
205 | ||
206 | play(move) { | |
207 | this.cmoves.push(this.getCmove(move)); | |
208 | super.play(move); | |
209 | } | |
210 | ||
211 | undo(move) { | |
212 | this.cmoves.pop(); | |
213 | super.undo(move); | |
214 | } | |
215 | ||
216 | atLeastOneMove() { | |
217 | return true; | |
31e9e40a BA |
218 | } |
219 | ||
220 | getCheckSquares() { | |
221 | return []; | |
222 | } | |
223 | ||
224 | getCurrentScore() { | |
225 | const color = this.turn; | |
226 | const kp = this.kingPos[color]; | |
227 | if (color == "w" && kp[0] == 0) | |
228 | return "0-1"; | |
229 | if (color == "b" && kp[0] == V.size.x - 1) | |
230 | return "1-0"; | |
231 | // King is not on the opposite edge: game not over | |
232 | return "*"; | |
233 | } | |
234 | ||
235 | evalPosition() { | |
236 | // Very simple criterion for now: kings position | |
237 | return this.kingPos["w"][0] + this.kingPos["b"][0]; | |
238 | } | |
71ef1664 BA |
239 | |
240 | getNotation(move) { | |
241 | // Translate final square | |
242 | const finalSquare = V.CoordsToSquare(move.end); | |
243 | ||
244 | const piece = this.getPiece(move.start.x, move.start.y); | |
245 | if (piece == V.PAWN) { | |
246 | // Pawn move | |
247 | let notation = ""; | |
248 | if (move.vanish.length == 2) { | |
249 | // Capture | |
250 | const startColumn = V.CoordToColumn(move.start.y); | |
251 | notation = startColumn + "x" + finalSquare; | |
252 | } | |
253 | else notation = finalSquare; | |
254 | return notation; | |
255 | } | |
256 | // Piece movement | |
257 | return ( | |
258 | piece.toUpperCase() + | |
259 | (move.vanish.length == 2 ? "x" : "") + | |
260 | finalSquare | |
261 | ); | |
262 | } | |
31e9e40a | 263 | }; |