Fix Hiddenqueen 'quasi-checkmate'
[vchess.git] / client / src / variants / Rampage.js
1 import { ChessRules } from "@/base_rules";
2
3 export class RampageRules extends ChessRules {
4
5 // Sum white pieces attacking a square, and remove black pieces count.
6 sumAttacks([x, y]) {
7 const getSign = (color) => {
8 return (color == 'w' ? 1 : -1);
9 };
10 let res = 0;
11 // Knights:
12 V.steps[V.KNIGHT].forEach(s => {
13 const [i, j] = [x + s[0], y + s[1]];
14 if (V.OnBoard(i, j) && this.getPiece(i, j) == V.KNIGHT)
15 res += getSign(this.getColor(i, j));
16 });
17 // Kings:
18 V.steps[V.ROOK].concat(V.steps[V.BISHOP]).forEach(s => {
19 const [i, j] = [x + s[0], y + s[1]];
20 if (V.OnBoard(i, j) && this.getPiece(i, j) == V.KING)
21 res += getSign(this.getColor(i, j));
22 });
23 // Pawns:
24 for (let c of ['w', 'b']) {
25 for (let shift of [-1, 1]) {
26 const sign = getSign(c);
27 const [i, j] = [x + sign, y + shift];
28 if (
29 V.OnBoard(i, j) &&
30 this.getPiece(i, j) == V.PAWN &&
31 this.getColor(i, j) == c
32 ) {
33 res += sign;
34 }
35 }
36 }
37 // Other pieces (sliders):
38 V.steps[V.ROOK].concat(V.steps[V.BISHOP]).forEach(s => {
39 let [i, j] = [x + s[0], y + s[1]];
40 let compatible = [V.QUEEN];
41 compatible.push(s[0] == 0 || s[1] == 0 ? V.ROOK : V.BISHOP);
42 let firstCol = undefined;
43 while (V.OnBoard(i, j)) {
44 if (this.board[i][j] != V.EMPTY) {
45 if (!(compatible.includes(this.getPiece(i, j)))) break;
46 const colIJ = this.getColor(i, j);
47 if (!firstCol) firstCol = colIJ;
48 if (colIJ == firstCol) res += getSign(colIJ);
49 else break;
50 }
51 i += s[0];
52 j += s[1];
53 }
54 });
55 return res;
56 }
57
58 getPotentialMovesFrom([x, y]) {
59 let moves = super.getPotentialMovesFrom([x, y]);
60 const color = this.turn;
61 if (this.getPiece(x, y) == V.KING && this.underCheck(color))
62 // The king under check can only move as usual
63 return moves;
64 // Remember current final squares to not add moves twice:
65 const destinations = {};
66 const lastRank = (color == 'w' ? 0 : 7);
67 const piece = this.getPiece(x, y);
68 moves.forEach(m => destinations[m.end.x + "_" + m.end.y] = true);
69 for (let i=0; i<8; i++) {
70 for (let j=0; j<8; j++) {
71 if (this.board[i][j] == V.EMPTY && !destinations[i + "_" + j]) {
72 const sa = this.sumAttacks([i, j]);
73 if (
74 ((color == 'w' && sa > 0) || (color == 'b' && sa < 0)) &&
75 (piece != V.PAWN || i != lastRank)
76 ) {
77 moves.push(this.getBasicMove([x, y], [i, j]));
78 }
79 }
80 }
81 }
82 return moves;
83 }
84
85 static get SEARCH_DEPTH() {
86 return 1;
87 }
88
89 };