Commit | Line | Data |
---|---|---|
0c3fe8a6 | 1 | import { ChessRules } from "@/base_rules"; |
32f6285e | 2 | import { BerolinaRules } from "@/variants/Berolina"; |
6808d7a1 | 3 | import { ArrayFun } from "@/utils/array"; |
0c3fe8a6 BA |
4 | import { randInt } from "@/utils/alea"; |
5 | ||
32f6285e | 6 | export class Antiking1Rules extends BerolinaRules { |
7e8a7ea1 | 7 | |
32f6285e BA |
8 | static get PawnSpecs() { |
9 | return Object.assign( | |
10 | {}, | |
11 | ChessRules.PawnSpecs, | |
12 | { twoSquares: false } | |
13 | ); | |
c583ef1c BA |
14 | } |
15 | ||
16 | static get HasCastle() { | |
17 | return false; | |
18 | } | |
19 | ||
6808d7a1 BA |
20 | static get ANTIKING() { |
21 | return "a"; | |
22 | } | |
dac39588 | 23 | |
6808d7a1 | 24 | static get PIECES() { |
dac39588 BA |
25 | return ChessRules.PIECES.concat([V.ANTIKING]); |
26 | } | |
27 | ||
241bf8f2 BA |
28 | getPpath(b) { |
29 | return b[1] == "a" ? "Antiking/" + b : b; | |
30 | } | |
31 | ||
6f2f9437 BA |
32 | static IsGoodPosition(position) { |
33 | if (!ChessRules.IsGoodPosition(position)) return false; | |
34 | const rows = position.split("/"); | |
35 | // Check that exactly one antiking of each color is there: | |
36 | let antikings = { 'a': 0, 'A': 0 }; | |
37 | for (let row of rows) { | |
38 | for (let i = 0; i < row.length; i++) | |
39 | if (['A','a'].includes(row[i])) antikings[row[i]]++; | |
40 | } | |
41 | if (Object.values(antikings).some(v => v != 1)) return false; | |
42 | return true; | |
43 | } | |
44 | ||
6808d7a1 | 45 | setOtherVariables(fen) { |
dac39588 | 46 | super.setOtherVariables(fen); |
6808d7a1 | 47 | this.antikingPos = { w: [-1, -1], b: [-1, -1] }; |
dac39588 | 48 | const rows = V.ParseFen(fen).position.split("/"); |
6808d7a1 | 49 | for (let i = 0; i < rows.length; i++) { |
dac39588 | 50 | let k = 0; |
6808d7a1 BA |
51 | for (let j = 0; j < rows[i].length; j++) { |
52 | switch (rows[i].charAt(j)) { | |
53 | case "a": | |
54 | this.antikingPos["b"] = [i, k]; | |
dac39588 | 55 | break; |
6808d7a1 BA |
56 | case "A": |
57 | this.antikingPos["w"] = [i, k]; | |
dac39588 | 58 | break; |
6808d7a1 | 59 | default: { |
e50a8025 | 60 | const num = parseInt(rows[i].charAt(j), 10); |
6808d7a1 BA |
61 | if (!isNaN(num)) k += num - 1; |
62 | } | |
dac39588 BA |
63 | } |
64 | k++; | |
65 | } | |
66 | } | |
67 | } | |
68 | ||
c583ef1c BA |
69 | // (Anti)King flags at 1 (true) if they can knight-jump |
70 | setFlags(fenflags) { | |
71 | this.kingFlags = { | |
72 | // King then antiking | |
73 | w: [...Array(2).fill(false)], | |
74 | b: [...Array(2).fill(false)] | |
75 | }; | |
76 | for (let c of ["w", "b"]) { | |
77 | for (let i = 0; i < 2; i++) | |
78 | this.kingFlags[c][i] = fenflags.charAt((c == "w" ? 0 : 2) + i) == "1"; | |
79 | } | |
80 | } | |
81 | ||
82 | aggregateFlags() { | |
83 | return this.kingFlags; | |
84 | } | |
85 | ||
86 | disaggregateFlags(flags) { | |
87 | this.kingFlags = flags; | |
88 | } | |
89 | ||
90 | getFlagsFen() { | |
91 | // Return kings flags | |
92 | let flags = ""; | |
93 | for (let c of ["w", "b"]) { | |
94 | for (let i = 0; i < 2; i++) flags += this.kingFlags[c][i] ? "1" : "0"; | |
95 | } | |
96 | return flags; | |
97 | } | |
98 | ||
6808d7a1 BA |
99 | canTake([x1, y1], [x2, y2]) { |
100 | const piece1 = this.getPiece(x1, y1); | |
101 | const piece2 = this.getPiece(x2, y2); | |
102 | const color1 = this.getColor(x1, y1); | |
103 | const color2 = this.getColor(x2, y2); | |
104 | return ( | |
105 | piece2 != "a" && | |
106 | ((piece1 != "a" && color1 != color2) || | |
107 | (piece1 == "a" && color1 == color2)) | |
108 | ); | |
dac39588 BA |
109 | } |
110 | ||
6808d7a1 | 111 | getPotentialMovesFrom([x, y]) { |
c583ef1c BA |
112 | let moves = []; |
113 | let addKnightJumps = false; | |
114 | const piece = this.getPiece(x, y); | |
115 | const color = this.getColor(x, y); | |
116 | if (piece == V.ANTIKING) { | |
117 | moves = this.getPotentialAntikingMoves([x, y]); | |
118 | addKnightJumps = this.kingFlags[color][1]; | |
119 | } else { | |
120 | moves = super.getPotentialMovesFrom([x, y]); | |
121 | if (piece == V.KING) addKnightJumps = this.kingFlags[color][0]; | |
122 | } | |
123 | if (addKnightJumps) { | |
124 | // Add potential knight jump to (anti)kings | |
125 | const knightJumps = super.getPotentialKnightMoves([x, y]); | |
126 | // Remove captures (TODO: could be done more efficiently...) | |
127 | moves = moves.concat(knightJumps.filter(m => m.vanish.length == 1)); | |
128 | } | |
129 | return moves; | |
130 | } | |
131 | ||
6808d7a1 | 132 | getPotentialAntikingMoves(sq) { |
c583ef1c | 133 | // The antiking moves like a king (only captured colors differ) |
6808d7a1 BA |
134 | return this.getSlideNJumpMoves( |
135 | sq, | |
136 | V.steps[V.ROOK].concat(V.steps[V.BISHOP]), | |
137 | "oneStep" | |
138 | ); | |
dac39588 BA |
139 | } |
140 | ||
68e19a44 | 141 | isAttacked(sq, color) { |
6808d7a1 | 142 | return ( |
68e19a44 BA |
143 | super.isAttacked(sq, color) || |
144 | this.isAttackedByAntiking(sq, color) | |
6808d7a1 | 145 | ); |
dac39588 BA |
146 | } |
147 | ||
68e19a44 BA |
148 | isAttackedByKing([x, y], color) { |
149 | // Antiking is not attacked by king: | |
150 | if (this.getPiece(x, y) == V.ANTIKING) return false; | |
6808d7a1 BA |
151 | return this.isAttackedBySlideNJump( |
152 | [x, y], | |
68e19a44 | 153 | color, |
6808d7a1 BA |
154 | V.KING, |
155 | V.steps[V.ROOK].concat(V.steps[V.BISHOP]), | |
156 | "oneStep" | |
157 | ); | |
dac39588 BA |
158 | } |
159 | ||
68e19a44 BA |
160 | isAttackedByAntiking([x, y], color) { |
161 | // (Anti)King is not attacked by antiking | |
162 | if ([V.KING, V.ANTIKING].includes(this.getPiece(x, y))) return false; | |
6808d7a1 BA |
163 | return this.isAttackedBySlideNJump( |
164 | [x, y], | |
68e19a44 | 165 | color, |
6808d7a1 BA |
166 | V.ANTIKING, |
167 | V.steps[V.ROOK].concat(V.steps[V.BISHOP]), | |
168 | "oneStep" | |
169 | ); | |
dac39588 BA |
170 | } |
171 | ||
6808d7a1 | 172 | underCheck(color) { |
dac39588 | 173 | const oppCol = V.GetOppCol(color); |
6808d7a1 | 174 | let res = |
68e19a44 BA |
175 | this.isAttacked(this.kingPos[color], oppCol) || |
176 | !this.isAttacked(this.antikingPos[color], oppCol); | |
dac39588 BA |
177 | return res; |
178 | } | |
179 | ||
af34341d BA |
180 | getCheckSquares() { |
181 | const color = this.turn; | |
c583ef1c BA |
182 | let res = []; |
183 | const oppCol = V.GetOppCol(color); | |
184 | if (this.isAttacked(this.kingPos[color], oppCol)) | |
185 | res.push(JSON.parse(JSON.stringify(this.kingPos[color]))); | |
186 | if (!this.isAttacked(this.antikingPos[color], oppCol)) | |
dac39588 BA |
187 | res.push(JSON.parse(JSON.stringify(this.antikingPos[color]))); |
188 | return res; | |
189 | } | |
190 | ||
3a2a7b5f BA |
191 | postPlay(move) { |
192 | super.postPlay(move); | |
dac39588 BA |
193 | const piece = move.vanish[0].p; |
194 | const c = move.vanish[0].c; | |
c583ef1c | 195 | // Update antiking position, and kings flags |
6808d7a1 | 196 | if (piece == V.ANTIKING) { |
dac39588 BA |
197 | this.antikingPos[c][0] = move.appear[0].x; |
198 | this.antikingPos[c][1] = move.appear[0].y; | |
c583ef1c BA |
199 | this.kingFlags[c][1] = false; |
200 | } else if (piece == V.KING) this.kingFlags[c][0] = false; | |
dac39588 BA |
201 | } |
202 | ||
3a2a7b5f BA |
203 | postUndo(move) { |
204 | super.postUndo(move); | |
dac39588 BA |
205 | const c = move.vanish[0].c; |
206 | if (move.vanish[0].p == V.ANTIKING) | |
207 | this.antikingPos[c] = [move.start.x, move.start.y]; | |
208 | } | |
209 | ||
dac39588 | 210 | static get VALUES() { |
a97bdbda BA |
211 | return Object.assign( |
212 | { a: 1000 }, | |
213 | ChessRules.VALUES | |
214 | ); | |
dac39588 BA |
215 | } |
216 | ||
c583ef1c BA |
217 | static GenRandInitFen() { |
218 | // Always deterministic setup | |
219 | return "2prbkqA/2p1nnbr/2pppppp/8/8/PPPPPP2/RBNN1P2/aQKBRP2 w 0 1111"; | |
dac39588 | 220 | } |
b83a675a BA |
221 | |
222 | static get SEARCH_DEPTH() { | |
223 | return 2; | |
224 | } | |
7e8a7ea1 | 225 | |
6808d7a1 | 226 | }; |