1 import { ChessRules
} from "@/base_rules";
2 import { BerolinaRules
} from "@/variants/Berolina";
3 import { ArrayFun
} from "@/utils/array";
4 import { randInt
} from "@/utils/alea";
6 export class Antiking1Rules
extends BerolinaRules
{
12 static get PawnSpecs() {
20 static get HasCastle() {
24 static get ANTIKING() {
29 return ChessRules
.PIECES
.concat([V
.ANTIKING
]);
33 return (['a', 'p'].includes(b
[1]) ? "Antiking/" : "") + b
;
36 static IsGoodPosition(position
) {
37 if (!ChessRules
.IsGoodPosition(position
)) return false;
38 const rows
= position
.split("/");
39 // Check that exactly one antiking of each color is there:
40 let antikings
= { 'a': 0, 'A': 0 };
41 for (let row
of rows
) {
42 for (let i
= 0; i
< row
.length
; i
++)
43 if (['A','a'].includes(row
[i
])) antikings
[row
[i
]]++;
45 if (Object
.values(antikings
).some(v
=> v
!= 1)) return false;
49 setOtherVariables(fen
) {
50 super.setOtherVariables(fen
);
51 this.antikingPos
= { w: [-1, -1], b: [-1, -1] };
52 const rows
= V
.ParseFen(fen
).position
.split("/");
53 for (let i
= 0; i
< rows
.length
; i
++) {
55 for (let j
= 0; j
< rows
[i
].length
; j
++) {
56 switch (rows
[i
].charAt(j
)) {
58 this.antikingPos
["b"] = [i
, k
];
61 this.antikingPos
["w"] = [i
, k
];
64 const num
= parseInt(rows
[i
].charAt(j
), 10);
65 if (!isNaN(num
)) k
+= num
- 1;
73 // (Anti)King flags at 1 (true) if they can knight-jump
77 w: [...Array(2).fill(false)],
78 b: [...Array(2).fill(false)]
80 for (let c
of ["w", "b"]) {
81 for (let i
= 0; i
< 2; i
++)
82 this.kingFlags
[c
][i
] = fenflags
.charAt((c
== "w" ? 0 : 2) + i
) == "1";
87 return this.kingFlags
;
90 disaggregateFlags(flags
) {
91 this.kingFlags
= flags
;
97 for (let c
of ["w", "b"]) {
98 for (let i
= 0; i
< 2; i
++) flags
+= this.kingFlags
[c
][i
] ? "1" : "0";
103 canTake([x1
, y1
], [x2
, y2
]) {
104 const piece1
= this.getPiece(x1
, y1
);
105 const piece2
= this.getPiece(x2
, y2
);
106 const color1
= this.getColor(x1
, y1
);
107 const color2
= this.getColor(x2
, y2
);
110 ((piece1
!= "a" && color1
!= color2
) ||
111 (piece1
== "a" && color1
== color2
))
115 getPotentialMovesFrom([x
, y
]) {
117 let addKnightJumps
= false;
118 const piece
= this.getPiece(x
, y
);
119 const color
= this.getColor(x
, y
);
120 if (piece
== V
.ANTIKING
) {
121 moves
= this.getPotentialAntikingMoves([x
, y
]);
122 addKnightJumps
= this.kingFlags
[color
][1];
124 moves
= super.getPotentialMovesFrom([x
, y
]);
125 if (piece
== V
.KING
) addKnightJumps
= this.kingFlags
[color
][0];
127 if (addKnightJumps
) {
128 // Add potential knight jump to (anti)kings
129 const knightJumps
= super.getPotentialKnightMoves([x
, y
]);
130 // Remove captures (TODO: could be done more efficiently...)
131 moves
= moves
.concat(knightJumps
.filter(m
=> m
.vanish
.length
== 1));
136 getPotentialAntikingMoves(sq
) {
137 // The antiking moves like a king (only captured colors differ)
138 return this.getSlideNJumpMoves(
139 sq
, V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), 1);
142 isAttacked(sq
, color
) {
144 super.isAttacked(sq
, color
) ||
145 this.isAttackedByAntiking(sq
, color
)
149 isAttackedByKing([x
, y
], color
) {
150 // Antiking is not attacked by king:
151 if (this.getPiece(x
, y
) == V
.ANTIKING
) return false;
152 return this.isAttackedBySlideNJump(
153 [x
, y
], color
, V
.KING
, V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), 1);
156 isAttackedByAntiking([x
, y
], color
) {
157 // (Anti)King is not attacked by antiking
158 if ([V
.KING
, V
.ANTIKING
].includes(this.getPiece(x
, y
))) return false;
159 return this.isAttackedBySlideNJump(
160 [x
, y
], color
, V
.ANTIKING
, V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), 1);
164 const oppCol
= V
.GetOppCol(color
);
166 this.isAttacked(this.kingPos
[color
], oppCol
) ||
167 !this.isAttacked(this.antikingPos
[color
], oppCol
);
172 const color
= this.turn
;
174 const oppCol
= V
.GetOppCol(color
);
175 if (this.isAttacked(this.kingPos
[color
], oppCol
))
176 res
.push(JSON
.parse(JSON
.stringify(this.kingPos
[color
])));
177 if (!this.isAttacked(this.antikingPos
[color
], oppCol
))
178 res
.push(JSON
.parse(JSON
.stringify(this.antikingPos
[color
])));
183 super.postPlay(move);
184 const piece
= move.vanish
[0].p
;
185 const c
= move.vanish
[0].c
;
186 // Update antiking position, and kings flags
187 if (piece
== V
.ANTIKING
) {
188 this.antikingPos
[c
][0] = move.appear
[0].x
;
189 this.antikingPos
[c
][1] = move.appear
[0].y
;
190 this.kingFlags
[c
][1] = false;
191 } else if (piece
== V
.KING
) this.kingFlags
[c
][0] = false;
195 super.postUndo(move);
196 const c
= move.vanish
[0].c
;
197 if (move.vanish
[0].p
== V
.ANTIKING
)
198 this.antikingPos
[c
] = [move.start
.x
, move.start
.y
];
201 static get VALUES() {
202 return Object
.assign(
208 static GenRandInitFen() {
209 // Always deterministic setup
210 return "2prbkqA/2p1nnbr/2pppppp/8/8/PPPPPP2/RBNN1P2/aQKBRP2 w 0 1111";
213 static get SEARCH_DEPTH() {