Fix castling prevention when passing on attacked squares
[xogo.git] / variants / Benedict / class.js
1 import ChessRules from "/base_rules.js";
2 import PiPo from "/utils/PiPo.js";
3
4 export default class BenedictRules extends ChessRules {
5
6 static get Options() {
7 return {
8 select: C.Options.select,
9 check: [],
10 styles: [
11 "balance",
12 "cylinder",
13 "dark",
14 "doublemove",
15 "progressive",
16 "zen"
17 ]
18 };
19 }
20
21 get hasEnpassant() {
22 return false;
23 }
24
25 canTake() {
26 return false;
27 }
28
29 // Find potential captures from a square
30 // follow steps from x,y until something is met.
31 findAttacks([x, y]) {
32 const [color, piece] = [this.getColor(x, y), this.getPiece(x, y)];
33 const oppCol = C.GetOppCol(color);
34 let squares = {};
35 const specs = this.pieces(color, x, y)[piece];
36 const attacks = specs.attack || specs.moves;
37 for (let a of attacks) {
38 outerLoop: for (let step of a.steps) {
39 let [i, j] = [x + step[0], this.computeY(y + step[1])];
40 let nbSteps = 1;
41 while (this.onBoard(i, j) && this.board[i][j] == "") {
42 if (a.range <= nbSteps++)
43 continue outerLoop;
44 i += step[0];
45 j = this.computeY(j + step[1]);
46 }
47 if (
48 this.onBoard(i, j) && this.getColor(i, j) == oppCol &&
49 (!this.options["zen"] || this.getPieceType(i, j) == "k")
50 ) {
51 squares[C.CoordsToSquare({x: i, y: j})] = true;
52 }
53 }
54 }
55 return Object.keys(squares);
56 }
57
58 postProcessPotentialMoves(moves) {
59 moves.forEach(m => {
60 super.playOnBoard(m);
61 let attacks = this.findAttacks([m.end.x, m.end.y])
62 if (this.options["zen"]) {
63 let endSquares = {};
64 super.findCapturesOn([m.end.x, m.end.y], {zen: true}).forEach(c => {
65 endSquares[C.CoordsToSquare(c.end)] = true;
66 });
67 Array.prototype.push.apply(attacks, Object.keys(endSquares));
68 }
69 super.undoOnBoard(m);
70 m.flips = [];
71 attacks.map(C.SquareToCoords).forEach(a => {
72 m.flips.push({x: a.x, y: a.y});
73 });
74 });
75 return moves;
76 }
77
78 playOnBoard(move) {
79 super.playOnBoard(move);
80 this.flipColorOf(move.flips);
81 }
82 undoOnBoard(move) {
83 super.undoOnBoard(move);
84 this.flipColorOf(move.flips);
85 }
86
87 flipColorOf(flips) {
88 for (let xy of flips) {
89 const newColor = C.GetOppCol(this.getColor(xy.x, xy.y));
90 this.board[xy.x][xy.y] = newColor + this.board[xy.x][xy.y][1];
91 }
92 }
93
94 postPlay(move) {
95 if (this.options["balance"] && [1, 3].includes(this.movesCount)) {
96 // If enemy king is flipped: game over
97 const oppCol = C.GetOppCol(move.vanish[0].c);
98 const oppKingPos = this.searchKingPos(oppCol);
99 if (oppKingPos[0] < 0) {
100 this.turn = oppCol;
101 this.movesCount++;
102 return;
103 }
104 }
105 super.postPlay(move);
106 }
107
108 // Moves cannot flip our king's color, so all are valid
109 filterValid(moves) {
110 return moves;
111 }
112
113 // A king under (regular) check flips color, and the game is over.
114 underCheck() {
115 return false;
116 }
117
118 playVisual(move, r) {
119 super.playVisual(move, r);
120 move.flips.forEach(f => {
121 this.g_pieces[f.x][f.y].classList.toggle("white");
122 this.g_pieces[f.x][f.y].classList.toggle("black");
123 });
124 }
125
126 };