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