d07474b3ef8e8918a42aeac0f7dad2f12b0a4dcb
1 import { ChessRules
, PiPo
, Move
} from "@/base_rules";
3 export class Allmate1Rules
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 // Avoid "oppMoves = this.getAllValidMoves();" => infinite recursion
42 outerLoop: for (let i
=0; i
<V
.size
.x
; i
++) {
43 for (let j
=0; j
<V
.size
.y
; j
++) {
44 if (this.getColor(i
,j
) == oppCol
) {
46 switch (this.getPiece(i
, j
)) {
48 oppMoves
= this.getPotentialPawnMoves([i
, j
]);
51 oppMoves
= this.getPotentialRookMoves([i
, j
]);
54 oppMoves
= this.getPotentialKnightMoves([i
, j
]);
57 oppMoves
= this.getPotentialBishopMoves([i
, j
]);
60 oppMoves
= this.getPotentialQueenMoves([i
, j
]);
63 oppMoves
= this.getPotentialKingMoves([i
, j
]);
66 for (let om
of oppMoves
) {
67 V
.PlayOnBoard(this.board
, om
);
68 Object
.values(attacked
).forEach(sq
=> {
69 const origSq
= [sq
[0], sq
[1]];
70 if (om
.start
.x
== sq
[0] && om
.start
.y
== sq
[1])
72 sq
= [om
.appear
[0].x
, om
.appear
[0].y
];
73 if (!this.isAttacked(sq
, color
))
74 delete attacked
[origSq
[0]+"_"+origSq
[1]];
76 V
.UndoOnBoard(this.board
, om
);
77 if (Object
.keys(attacked
).length
== 0)
78 // No need to explore more moves
85 // 3) Add mate-captures:
86 Object
.values(attacked
).forEach(sq
=> {
87 m
.vanish
.push(new PiPo({
91 p: this.getPiece(sq
[0], sq
[1])
101 // No "under check" conditions in castling
103 return super.getCastleMoves(sq
, "castleInCheck");
106 // TODO: allow pieces to "commit suicide"? (Currently yes except king)
108 // Remove moves which let the king mate-captured:
109 if (moves
.length
== 0) return [];
110 const color
= this.turn
;
111 const oppCol
= V
.GetOppCol(color
);
112 return moves
.filter(m
=> {
115 if (this.underCheck(color
)) {
117 const attacked
= this.kingPos
[color
];
118 // Try to find a move to escape check
119 // TODO: very inefficient method.
120 outerLoop: for (let i
=0; i
<V
.size
.x
; i
++) {
121 for (let j
=0; j
<V
.size
.y
; j
++) {
122 if (this.getColor(i
,j
) == color
) {
124 // Artficial turn change to "play twice":
126 switch (this.getPiece(i
, j
)) {
128 emoves
= this.getPotentialPawnMoves([i
, j
]);
131 emoves
= this.getPotentialRookMoves([i
, j
]);
134 emoves
= this.getPotentialKnightMoves([i
, j
]);
137 emoves
= this.getPotentialBishopMoves([i
, j
]);
140 emoves
= this.getPotentialQueenMoves([i
, j
]);
143 emoves
= this.getPotentialKingMoves([i
, j
]);
147 for (let em
of emoves
) {
148 V
.PlayOnBoard(this.board
, em
);
150 if (em
.start
.x
== attacked
[0] && em
.start
.y
== attacked
[1])
152 sq
= [em
.appear
[0].x
, em
.appear
[0].y
];
153 if (!this.isAttacked(sq
, oppCol
))
155 V
.UndoOnBoard(this.board
, em
);
157 // No need to explore more moves
170 super.postPlay(move);
171 if (move.vanish
.length
>= 2 && move.appear
.length
== 1) {
172 for (let i
= 1; i
<move.vanish
.length
; i
++) {
173 const v
= move.vanish
[i
];
174 // Did opponent king disappeared?
176 this.kingPos
[this.turn
] = [-1, -1];
178 else if (v
.p
== V
.ROOK
) {
179 if (v
.y
< this.INIT_COL_KING
[v
.c
])
180 this.castleFlags
[v
.c
][0] = 8;
182 // v.y > this.INIT_COL_KING[v.c]
183 this.castleFlags
[v
.c
][1] = 8;
191 const oppCol
= this.turn
;
192 if (move.vanish
.length
>= 2 && move.appear
.length
== 1) {
193 // Did opponent king disappeared?
194 const psq
= move.vanish
.find(v
=> v
.p
== V
.KING
&& v
.c
== oppCol
)
196 this.kingPos
[psq
.c
] = [psq
.x
, psq
.y
];
201 const color
= this.turn
;
202 const kp
= this.kingPos
[color
];
205 return color
== "w" ? "0-1" : "1-0";
206 if (this.atLeastOneMove()) return "*";
207 // Kings still there, no moves:
211 static get SEARCH_DEPTH() {
216 let notation
= super.getNotation(move);
217 // Add a capture mark (not describing what is captured...):
218 if (move.vanish
.length
> 1 && move.appear
.length
== 1) {
219 if (!!(notation
.match(/^[a-h]x/)))
220 // Pawn capture: remove initial "b" in bxc4 for example
221 notation
= notation
.substr(1);
222 notation
= notation
.replace("x","") + "X";