1 import { ChessRules
, Move
, PiPo
} from "@/base_rules";
3 export class CannibalRules
extends ChessRules
{
4 static get KING_CODE() {
14 static get KING_DECODE() {
24 // Kings may be disguised:
26 const piece
= this.board
[x
][y
].charAt(1);
27 if (Object
.keys(V
.KING_DECODE
).includes(piece
))
28 return V
.KING_DECODE
[piece
];
33 return (Object
.keys(V
.KING_DECODE
).includes(b
[1]) ? "Cannibal/" : "") + b
;
36 // Kings may be disguised:
37 setOtherVariables(fen
) {
38 super.setOtherVariables(fen
);
39 const rows
= V
.ParseFen(fen
).position
.split("/");
40 if (this.kingPos
["w"][0] < 0 || this.kingPos
["b"][0] < 0) {
41 for (let i
= 0; i
< rows
.length
; i
++) {
42 let k
= 0; //column index on board
43 for (let j
= 0; j
< rows
[i
].length
; j
++) {
44 const piece
= rows
[i
].charAt(j
);
45 if (Object
.keys(V
.KING_DECODE
).includes(piece
.toLowerCase())) {
46 const color
= (piece
.charCodeAt(0) <= 90 ? 'w' : 'b');
47 this.kingPos
[color
] = [i
, k
];
49 const num
= parseInt(rows
[i
].charAt(j
));
50 if (!isNaN(num
)) k
+= num
- 1;
58 // Trim all non-capturing moves
59 static KeepCaptures(moves
) {
60 return moves
.filter(m
=> m
.vanish
.length
== 2 && m
.appear
.length
== 1);
63 // Stop at the first capture found (if any)
65 const color
= this.turn
;
66 const oppCol
= V
.GetOppCol(color
);
67 for (let i
= 0; i
< V
.size
.x
; i
++) {
68 for (let j
= 0; j
< V
.size
.y
; j
++) {
70 this.board
[i
][j
] != V
.EMPTY
&&
71 this.getColor(i
, j
) != oppCol
&&
72 this.filterValid(this.getPotentialMovesFrom([i
, j
])).some(m
=>
73 // Warning: discard castle moves
74 m
.vanish
.length
== 2 && m
.appear
.length
== 1)
83 // Because of the disguised kings, getPiece() could be wrong:
84 // use board[x][y][1] instead (always valid).
85 getBasicMove([sx
, sy
], [ex
, ey
], tr
) {
86 const initColor
= this.getColor(sx
, sy
);
87 const initPiece
= this.board
[sx
][sy
].charAt(1);
93 c: tr
? tr
.c : initColor
,
94 p: tr
? tr
.p : initPiece
107 // The opponent piece disappears if we take it
108 if (this.board
[ex
][ey
] != V
.EMPTY
) {
113 c: this.getColor(ex
, ey
),
114 p: this.board
[ex
][ey
].charAt(1)
118 // If the captured piece has a different nature: take it as well
119 if (mv
.vanish
[0].p
!= mv
.vanish
[1].p
) {
121 mv
.vanish
[0].p
== V
.KING
||
122 Object
.keys(V
.KING_DECODE
).includes(mv
.vanish
[0].p
)
124 mv
.appear
[0].p
= V
.KING_CODE
[mv
.vanish
[1].p
];
125 } else mv
.appear
[0].p
= mv
.vanish
[1].p
;
128 else if (!!tr
&& mv
.vanish
[0].p
!= V
.PAWN
)
129 // Special case of a non-capturing king-as-pawn promotion
130 mv
.appear
[0].p
= V
.KING_CODE
[tr
.p
];
135 getPotentialMovesFrom([x
, y
]) {
136 const piece
= this.board
[x
][y
].charAt(1);
137 if (Object
.keys(V
.KING_DECODE
).includes(piece
))
138 return super.getPotentialMovesFrom([x
, y
], V
.KING_DECODE
[piece
]);
139 return super.getPotentialMovesFrom([x
, y
], piece
);
142 addPawnMoves([x1
, y1
], [x2
, y2
], moves
) {
143 let finalPieces
= [V
.PAWN
];
144 const color
= this.turn
;
145 const lastRank
= (color
== "w" ? 0 : V
.size
.x
- 1);
146 if (x2
== lastRank
) {
147 if (this.board
[x2
][y2
] != V
.EMPTY
)
148 // Cannibal rules: no choice if capture
149 finalPieces
= [this.getPiece(x2
, y2
)];
150 else finalPieces
= V
.PawnSpecs
.promotions
;
153 for (let piece
of finalPieces
) {
154 tr
= (piece
!= V
.PAWN
? { c: color
, p: piece
} : null);
155 moves
.push(this.getBasicMove([x1
, y1
], [x2
, y2
], tr
));
159 getPossibleMovesFrom(sq
) {
160 let moves
= this.filterValid(this.getPotentialMovesFrom(sq
));
161 const captureMoves
= V
.KeepCaptures(moves
);
162 if (captureMoves
.length
> 0) return captureMoves
;
163 if (this.atLeastOneCapture()) return [];
168 const moves
= super.getAllValidMoves();
169 if (moves
.some(m
=> m
.vanish
.length
== 2)) return V
.KeepCaptures(moves
);
174 const c
= V
.GetOppCol(this.turn
);
175 const piece
= move.appear
[0].p
;
176 // Update king position + flags
177 if (piece
== V
.KING
|| Object
.keys(V
.KING_DECODE
).includes(piece
)) {
178 this.kingPos
[c
][0] = move.appear
[0].x
;
179 this.kingPos
[c
][1] = move.appear
[0].y
;
180 this.castleFlags
[c
] = [V
.size
.y
, V
.size
.y
];
183 super.updateCastleFlags(move);
187 // (Potentially) Reset king position
188 const c
= this.getColor(move.start
.x
, move.start
.y
);
189 const piece
= move.appear
[0].p
;
190 if (piece
== V
.KING
|| Object
.keys(V
.KING_DECODE
).includes(piece
))
191 this.kingPos
[c
] = [move.start
.x
, move.start
.y
];
194 static get VALUES() {
205 static get SEARCH_DEPTH() {