Fix Antiking 1 notation
[vchess.git] / client / src / variants / Antiking1.js
CommitLineData
0c3fe8a6 1import { ChessRules } from "@/base_rules";
6808d7a1 2import { ArrayFun } from "@/utils/array";
0c3fe8a6
BA
3import { randInt } from "@/utils/alea";
4
c583ef1c
BA
5export const VariantRules = class Antiking1Rules extends ChessRules {
6 static get HasEnpassant() {
7 return false;
8 }
9
10 static get HasCastle() {
11 return false;
12 }
13
6808d7a1
BA
14 static get ANTIKING() {
15 return "a";
16 }
dac39588 17
6808d7a1 18 static get PIECES() {
dac39588
BA
19 return ChessRules.PIECES.concat([V.ANTIKING]);
20 }
21
241bf8f2
BA
22 getPpath(b) {
23 return b[1] == "a" ? "Antiking/" + b : b;
24 }
25
6808d7a1 26 setOtherVariables(fen) {
dac39588 27 super.setOtherVariables(fen);
6808d7a1 28 this.antikingPos = { w: [-1, -1], b: [-1, -1] };
dac39588 29 const rows = V.ParseFen(fen).position.split("/");
6808d7a1 30 for (let i = 0; i < rows.length; i++) {
dac39588 31 let k = 0;
6808d7a1
BA
32 for (let j = 0; j < rows[i].length; j++) {
33 switch (rows[i].charAt(j)) {
34 case "a":
35 this.antikingPos["b"] = [i, k];
dac39588 36 break;
6808d7a1
BA
37 case "A":
38 this.antikingPos["w"] = [i, k];
dac39588 39 break;
6808d7a1 40 default: {
dac39588 41 const num = parseInt(rows[i].charAt(j));
6808d7a1
BA
42 if (!isNaN(num)) k += num - 1;
43 }
dac39588
BA
44 }
45 k++;
46 }
47 }
48 }
49
c583ef1c
BA
50 // (Anti)King flags at 1 (true) if they can knight-jump
51 setFlags(fenflags) {
52 this.kingFlags = {
53 // King then antiking
54 w: [...Array(2).fill(false)],
55 b: [...Array(2).fill(false)]
56 };
57 for (let c of ["w", "b"]) {
58 for (let i = 0; i < 2; i++)
59 this.kingFlags[c][i] = fenflags.charAt((c == "w" ? 0 : 2) + i) == "1";
60 }
61 }
62
63 aggregateFlags() {
64 return this.kingFlags;
65 }
66
67 disaggregateFlags(flags) {
68 this.kingFlags = flags;
69 }
70
71 getFlagsFen() {
72 // Return kings flags
73 let flags = "";
74 for (let c of ["w", "b"]) {
75 for (let i = 0; i < 2; i++) flags += this.kingFlags[c][i] ? "1" : "0";
76 }
77 return flags;
78 }
79
6808d7a1
BA
80 canTake([x1, y1], [x2, y2]) {
81 const piece1 = this.getPiece(x1, y1);
82 const piece2 = this.getPiece(x2, y2);
83 const color1 = this.getColor(x1, y1);
84 const color2 = this.getColor(x2, y2);
85 return (
86 piece2 != "a" &&
87 ((piece1 != "a" && color1 != color2) ||
88 (piece1 == "a" && color1 == color2))
89 );
dac39588
BA
90 }
91
6808d7a1 92 getPotentialMovesFrom([x, y]) {
c583ef1c
BA
93 let moves = [];
94 let addKnightJumps = false;
95 const piece = this.getPiece(x, y);
96 const color = this.getColor(x, y);
97 if (piece == V.ANTIKING) {
98 moves = this.getPotentialAntikingMoves([x, y]);
99 addKnightJumps = this.kingFlags[color][1];
100 } else {
101 moves = super.getPotentialMovesFrom([x, y]);
102 if (piece == V.KING) addKnightJumps = this.kingFlags[color][0];
103 }
104 if (addKnightJumps) {
105 // Add potential knight jump to (anti)kings
106 const knightJumps = super.getPotentialKnightMoves([x, y]);
107 // Remove captures (TODO: could be done more efficiently...)
108 moves = moves.concat(knightJumps.filter(m => m.vanish.length == 1));
109 }
110 return moves;
111 }
112
113 getPotentialPawnMoves([x, y]) {
114 const color = this.turn;
115 let moves = [];
116 const [sizeX, sizeY] = [V.size.x, V.size.y];
117 const shiftX = color == "w" ? -1 : 1;
118 const startRank = color == "w" ? sizeX - 2 : 1;
119 const lastRank = color == "w" ? 0 : sizeX - 1;
120 const finalPieces =
121 x + shiftX == lastRank ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN] : [V.PAWN];
122
123 // One square diagonally
124 for (let shiftY of [-1, 1]) {
125 if (this.board[x + shiftX][y + shiftY] == V.EMPTY) {
126 for (let piece of finalPieces) {
127 moves.push(
128 this.getBasicMove([x, y], [x + shiftX, y + shiftY], {
129 c: color,
130 p: piece
131 })
132 );
133 }
134 }
dac39588 135 }
c583ef1c
BA
136 // Capture
137 if (
138 this.board[x + shiftX][y] != V.EMPTY &&
139 this.canTake([x, y], [x + shiftX, y])
140 ) {
141 for (let piece of finalPieces)
142 moves.push(
143 this.getBasicMove([x, y], [x + shiftX, y], { c: color, p: piece })
144 );
145 }
146
147 return moves;
dac39588
BA
148 }
149
6808d7a1 150 getPotentialAntikingMoves(sq) {
c583ef1c 151 // The antiking moves like a king (only captured colors differ)
6808d7a1
BA
152 return this.getSlideNJumpMoves(
153 sq,
154 V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
155 "oneStep"
156 );
dac39588
BA
157 }
158
68e19a44 159 isAttacked(sq, color) {
6808d7a1 160 return (
68e19a44
BA
161 super.isAttacked(sq, color) ||
162 this.isAttackedByAntiking(sq, color)
6808d7a1 163 );
dac39588
BA
164 }
165
c583ef1c
BA
166 isAttackedByPawn([x, y], color) {
167 let pawnShift = (color == "w" ? 1 : -1);
168 if (x + pawnShift >= 0 && x + pawnShift < V.size.x) {
169 if (
170 this.getPiece(x + pawnShift, y) == V.PAWN &&
171 this.getColor(x + pawnShift, y) == color
172 ) {
173 return true;
174 }
175 }
176 return false;
177 }
178
68e19a44
BA
179 isAttackedByKing([x, y], color) {
180 // Antiking is not attacked by king:
181 if (this.getPiece(x, y) == V.ANTIKING) return false;
6808d7a1
BA
182 return this.isAttackedBySlideNJump(
183 [x, y],
68e19a44 184 color,
6808d7a1
BA
185 V.KING,
186 V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
187 "oneStep"
188 );
dac39588
BA
189 }
190
68e19a44
BA
191 isAttackedByAntiking([x, y], color) {
192 // (Anti)King is not attacked by antiking
193 if ([V.KING, V.ANTIKING].includes(this.getPiece(x, y))) return false;
6808d7a1
BA
194 return this.isAttackedBySlideNJump(
195 [x, y],
68e19a44 196 color,
6808d7a1
BA
197 V.ANTIKING,
198 V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
199 "oneStep"
200 );
dac39588
BA
201 }
202
6808d7a1 203 underCheck(color) {
dac39588 204 const oppCol = V.GetOppCol(color);
6808d7a1 205 let res =
68e19a44
BA
206 this.isAttacked(this.kingPos[color], oppCol) ||
207 !this.isAttacked(this.antikingPos[color], oppCol);
dac39588
BA
208 return res;
209 }
210
6808d7a1 211 getCheckSquares(color) {
c583ef1c
BA
212 let res = [];
213 const oppCol = V.GetOppCol(color);
214 if (this.isAttacked(this.kingPos[color], oppCol))
215 res.push(JSON.parse(JSON.stringify(this.kingPos[color])));
216 if (!this.isAttacked(this.antikingPos[color], oppCol))
dac39588
BA
217 res.push(JSON.parse(JSON.stringify(this.antikingPos[color])));
218 return res;
219 }
220
3a2a7b5f
BA
221 postPlay(move) {
222 super.postPlay(move);
dac39588
BA
223 const piece = move.vanish[0].p;
224 const c = move.vanish[0].c;
c583ef1c 225 // Update antiking position, and kings flags
6808d7a1 226 if (piece == V.ANTIKING) {
dac39588
BA
227 this.antikingPos[c][0] = move.appear[0].x;
228 this.antikingPos[c][1] = move.appear[0].y;
c583ef1c
BA
229 this.kingFlags[c][1] = false;
230 } else if (piece == V.KING) this.kingFlags[c][0] = false;
dac39588
BA
231 }
232
3a2a7b5f
BA
233 postUndo(move) {
234 super.postUndo(move);
dac39588
BA
235 const c = move.vanish[0].c;
236 if (move.vanish[0].p == V.ANTIKING)
237 this.antikingPos[c] = [move.start.x, move.start.y];
238 }
239
6808d7a1
BA
240 getCurrentScore() {
241 if (this.atLeastOneMove())
0c3fe8a6
BA
242 return "*";
243
244 const color = this.turn;
dac39588 245 const oppCol = V.GetOppCol(color);
6808d7a1 246 if (
68e19a44
BA
247 !this.isAttacked(this.kingPos[color], oppCol) &&
248 this.isAttacked(this.antikingPos[color], oppCol)
6808d7a1 249 ) {
dac39588
BA
250 return "1/2";
251 }
252 return color == "w" ? "0-1" : "1-0";
253 }
254
255 static get VALUES() {
a97bdbda
BA
256 return Object.assign(
257 { a: 1000 },
258 ChessRules.VALUES
259 );
dac39588
BA
260 }
261
c583ef1c
BA
262 static GenRandInitFen() {
263 // Always deterministic setup
264 return "2prbkqA/2p1nnbr/2pppppp/8/8/PPPPPP2/RBNN1P2/aQKBRP2 w 0 1111";
dac39588 265 }
b83a675a
BA
266
267 static get SEARCH_DEPTH() {
268 return 2;
269 }
11482348
BA
270
271 // TODO: notation copied from Berolina
272 getNotation(move) {
273 const piece = this.getPiece(move.start.x, move.start.y);
274 if (piece == V.PAWN) {
275 // Pawn move
276 const finalSquare = V.CoordsToSquare(move.end);
277 let notation = "";
278 if (move.vanish.length == 2)
279 //capture
280 notation = "Px" + finalSquare;
281 else {
282 // No capture: indicate the initial square for potential ambiguity
283 const startSquare = V.CoordsToSquare(move.start);
284 notation = startSquare + finalSquare;
285 }
286 if (move.appear[0].p != V.PAWN)
287 // Promotion
288 notation += "=" + move.appear[0].p.toUpperCase();
289 return notation;
290 }
291 return super.getNotation(move); //all other pieces are orthodox
292 }
6808d7a1 293};