1 import { ChessRules
, PiPo
, Move
} from "@/base_rules";
3 export class Allmate2Rules
extends ChessRules
{
4 static get HasEnpassant() {
13 static GenRandInitFen(randomness
) {
14 return ChessRules
.GenRandInitFen(randomness
).slice(0, -2);
17 getPotentialMovesFrom([x
, y
]) {
18 let moves
= super.getPotentialMovesFrom([x
, y
]);
19 // Remove standard captures (without removing castling):
20 moves
= moves
.filter(m
=> {
21 return m
.vanish
.length
== 1 || m
.appear
.length
== 2;
24 // Augment moves with "mate-captures":
25 // TODO: this is coded in a highly inefficient way...
26 const color
= this.turn
;
27 const oppCol
= V
.GetOppCol(this.turn
);
31 // 1) What is attacked?
33 for (let i
=0; i
<V
.size
.x
; i
++) {
34 for (let j
=0; j
<V
.size
.y
; j
++) {
35 if (this.getColor(i
,j
) == oppCol
&& this.isAttacked([i
,j
], color
))
36 attacked
[i
+"_"+j
] = [i
,j
];
40 // 2) Among attacked pieces, which cannot escape capture?
41 // --> without (normal-)capturing: difference with Allmate1 variant
42 // Avoid "oppMoves = this.getAllValidMoves();" => infinite recursion
43 outerLoop: for (let i
=0; i
<V
.size
.x
; i
++) {
44 for (let j
=0; j
<V
.size
.y
; j
++) {
45 if (this.getColor(i
,j
) == oppCol
) {
47 switch (this.getPiece(i
, j
)) {
49 oppMoves
= this.getPotentialPawnMoves([i
, j
]);
52 oppMoves
= this.getPotentialRookMoves([i
, j
]);
55 oppMoves
= this.getPotentialKnightMoves([i
, j
]);
58 oppMoves
= this.getPotentialBishopMoves([i
, j
]);
61 oppMoves
= this.getPotentialQueenMoves([i
, j
]);
64 oppMoves
= this.getPotentialKingMoves([i
, j
]);
67 for (let om
of oppMoves
) {
68 if (om
.vanish
.length
== 2 && om
.appear
.length
== 1)
69 // Skip captures: forbidden in this mode
71 V
.PlayOnBoard(this.board
, om
);
72 Object
.values(attacked
).forEach(sq
=> {
73 const origSq
= [sq
[0], sq
[1]];
74 if (om
.start
.x
== sq
[0] && om
.start
.y
== sq
[1])
76 sq
= [om
.appear
[0].x
, om
.appear
[0].y
];
77 if (!this.isAttacked(sq
, color
))
78 delete attacked
[origSq
[0]+"_"+origSq
[1]];
80 V
.UndoOnBoard(this.board
, om
);
81 if (Object
.keys(attacked
).length
== 0)
82 // No need to explore more moves
89 // 3) Add mate-captures:
90 Object
.values(attacked
).forEach(sq
=> {
91 m
.vanish
.push(new PiPo({
95 p: this.getPiece(sq
[0], sq
[1])
105 // No "under check" conditions in castling
107 return super.getCastleMoves(sq
, "castleInCheck");
110 // TODO: allow pieces to "commit suicide"? (Currently yes except king)
112 // Remove moves which let the king mate-captured:
113 if (moves
.length
== 0) return [];
114 const color
= this.turn
;
115 const oppCol
= V
.GetOppCol(color
);
116 return moves
.filter(m
=> {
119 if (this.underCheck(color
)) {
121 const attacked
= this.kingPos
[color
];
122 // Try to find a move to escape check
123 // TODO: very inefficient method.
124 outerLoop: for (let i
=0; i
<V
.size
.x
; i
++) {
125 for (let j
=0; j
<V
.size
.y
; j
++) {
126 if (this.getColor(i
,j
) == color
) {
128 // Artficial turn change to "play twice":
130 switch (this.getPiece(i
, j
)) {
132 emoves
= this.getPotentialPawnMoves([i
, j
]);
135 emoves
= this.getPotentialRookMoves([i
, j
]);
138 emoves
= this.getPotentialKnightMoves([i
, j
]);
141 emoves
= this.getPotentialBishopMoves([i
, j
]);
144 emoves
= this.getPotentialQueenMoves([i
, j
]);
147 emoves
= this.getPotentialKingMoves([i
, j
]);
151 for (let em
of emoves
) {
152 V
.PlayOnBoard(this.board
, em
);
154 if (em
.start
.x
== attacked
[0] && em
.start
.y
== attacked
[1])
156 sq
= [em
.appear
[0].x
, em
.appear
[0].y
];
157 if (!this.isAttacked(sq
, oppCol
))
159 V
.UndoOnBoard(this.board
, em
);
161 // No need to explore more moves
174 super.postPlay(move);
175 if (move.vanish
.length
>= 2 && move.appear
.length
== 1) {
176 for (let i
= 1; i
<move.vanish
.length
; i
++) {
177 const v
= move.vanish
[i
];
178 // Did opponent king disappeared?
180 this.kingPos
[this.turn
] = [-1, -1];
182 else if (v
.p
== V
.ROOK
) {
183 if (v
.y
< this.INIT_COL_KING
[v
.c
])
184 this.castleFlags
[v
.c
][0] = 8;
186 // v.y > this.INIT_COL_KING[v.c]
187 this.castleFlags
[v
.c
][1] = 8;
195 const oppCol
= this.turn
;
196 if (move.vanish
.length
>= 2 && move.appear
.length
== 1) {
197 // Did opponent king disappeared?
198 const psq
= move.vanish
.find(v
=> v
.p
== V
.KING
&& v
.c
== oppCol
)
200 this.kingPos
[psq
.c
] = [psq
.x
, psq
.y
];
205 const color
= this.turn
;
206 const kp
= this.kingPos
[color
];
209 return color
== "w" ? "0-1" : "1-0";
210 if (this.atLeastOneMove())
212 // Kings still there, no moves:
216 static get SEARCH_DEPTH() {
221 let notation
= super.getNotation(move);
222 // Add a capture mark (not describing what is captured...):
223 if (move.vanish
.length
> 1 && move.appear
.length
== 1) {
224 if (!!(notation
.match(/^[a-h]x/)))
225 // Pawn capture: remove initial "b" in bxc4 for example
226 notation
= notation
.substr(1);
227 notation
= notation
.replace("x","") + "X";