Add Fugue variant
[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 6export 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};