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