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