Add temporary patch for preset challenges
[vchess.git] / client / src / variants / Benedict.js
1 import { ChessRules, PiPo, Move } from "@/base_rules";
2
3 export class BenedictRules extends ChessRules {
4
5 static get HasEnpassant() {
6 return false;
7 }
8
9 static get PawnSpecs() {
10 return Object.assign(
11 {},
12 ChessRules.PawnSpecs,
13 { canCapture: false }
14 );
15 }
16
17 // TODO(?): some duplicated code in 2 next functions
18 getSlideNJumpMoves([x, y], steps, oneStep) {
19 let moves = [];
20 outerLoop: for (let loop = 0; loop < steps.length; loop++) {
21 const step = steps[loop];
22 let i = x + step[0];
23 let j = y + step[1];
24 while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
25 moves.push(this.getBasicMove([x, y], [i, j]));
26 if (oneStep) continue outerLoop;
27 i += step[0];
28 j += step[1];
29 }
30 // No capture check: handled elsewhere (next method)
31 }
32 return moves;
33 }
34
35 // Find possible captures from a square
36 // follow steps from x,y until something is met.
37 findCaptures([x, y]) {
38 const color = this.getColor(x, y);
39 const piece = this.getPiece(x, y);
40 let squares = [];
41 const steps =
42 piece != V.PAWN
43 ? [V.QUEEN,V.KING].includes(piece)
44 ? V.steps[V.ROOK].concat(V.steps[V.BISHOP])
45 : V.steps[piece]
46 : color == "w"
47 ? [
48 [-1, -1],
49 [-1, 1]
50 ]
51 : [
52 [1, -1],
53 [1, 1]
54 ];
55 const oneStep = [V.KNIGHT,V.PAWN,V.KING].includes(piece);
56 outerLoop: for (let loop = 0; loop < steps.length; loop++) {
57 const step = steps[loop];
58 let i = x + step[0];
59 let j = y + step[1];
60 while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
61 if (oneStep) continue outerLoop;
62 i += step[0];
63 j += step[1];
64 }
65 if (
66 V.OnBoard(i, j) &&
67 this.getColor(i, j) == V.GetOppCol(color)
68 ) {
69 // eat!
70 squares.push([i, j]);
71 }
72 }
73 return squares;
74 }
75
76 // TODO: appear/vanish description of a move is too verbose for Benedict.
77 // => Would need a new "flipped" array, to be passed in Game.vue...
78 getPotentialMovesFrom([x, y]) {
79 const color = this.turn;
80 const oppCol = V.GetOppCol(color);
81 // Get all moves from x,y without captures:
82 let moves = super.getPotentialMovesFrom([x, y]);
83 // Add flips:
84 moves.forEach(m => {
85 let newAppear = [];
86 let newVanish = [];
87 V.PlayOnBoard(this.board, m);
88 // If castling, m.appear has 2 elements.
89 // In this case, consider the attacks of moving units only.
90 // (Sometimes the king or rook doesn't move).
91 for (let i = 0; i < m.appear.length; i++) {
92 const a = m.appear[i];
93 if (m.vanish[i].x != a.x || m.vanish[i].y != a.y) {
94 const flipped = this.findCaptures([a.x, a.y]);
95 flipped.forEach(sq => {
96 const piece = this.getPiece(sq[0],sq[1]);
97 const pipoA = new PiPo({
98 x:sq[0],
99 y:sq[1],
100 c:color,
101 p:piece
102 });
103 const pipoV = new PiPo({
104 x:sq[0],
105 y:sq[1],
106 c:oppCol,
107 p:piece
108 });
109 newAppear.push(pipoA);
110 newVanish.push(pipoV);
111 });
112 }
113 }
114 Array.prototype.push.apply(m.appear, newAppear);
115 Array.prototype.push.apply(m.vanish, newVanish);
116 V.UndoOnBoard(this.board, m);
117 });
118 return moves;
119 }
120
121 // Moves cannot flip our king's color, so all are valid
122 filterValid(moves) {
123 return moves;
124 }
125
126 // Since it's used just for the king, and there are no captures:
127 isAttacked(sq, color) {
128 return false;
129 }
130
131 // No notion of check here:
132 getCheckSquares() {
133 return [];
134 }
135
136 // Stop at the first move found
137 atLeastOneMove() {
138 const color = this.turn;
139 for (let i = 0; i < V.size.x; i++) {
140 for (let j = 0; j < V.size.y; j++) {
141 if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) {
142 if (this.getPotentialMovesFrom([i, j]).length > 0) return true;
143 }
144 }
145 }
146 return false;
147 }
148
149 getCurrentScore() {
150 const color = this.turn;
151 // Did a king change color?
152 const kp = this.kingPos[color];
153 if (this.getColor(kp[0], kp[1]) != color)
154 return color == "w" ? "0-1" : "1-0";
155 if (this.atLeastOneMove()) return "*";
156 // Stalemate:
157 return "1/2";
158 }
159
160 getNotation(move) {
161 // Just remove flips:
162 const basicMove = {
163 appear: [move.appear[0]],
164 vanish: [move.vanish[0]],
165 start: move.start,
166 end: move.end
167 };
168 return super.getNotation(basicMove);
169 }
170
171 };