Style
[vchess.git] / client / src / variants / Extinction.js
1 import { ChessRules } from "@/base_rules";
2
3 export const VariantRules = class ExtinctionRules extends ChessRules {
4 setOtherVariables(fen) {
5 super.setOtherVariables(fen);
6 const pos = V.ParseFen(fen).position;
7 // NOTE: no need for safety "|| []", because each piece type must be present
8 // (otherwise game is already over!)
9 this.material = {
10 w: {
11 [V.KING]: pos.match(/K/g).length,
12 [V.QUEEN]: pos.match(/Q/g).length,
13 [V.ROOK]: pos.match(/R/g).length,
14 [V.KNIGHT]: pos.match(/N/g).length,
15 [V.BISHOP]: pos.match(/B/g).length,
16 [V.PAWN]: pos.match(/P/g).length
17 },
18 b: {
19 [V.KING]: pos.match(/k/g).length,
20 [V.QUEEN]: pos.match(/q/g).length,
21 [V.ROOK]: pos.match(/r/g).length,
22 [V.KNIGHT]: pos.match(/n/g).length,
23 [V.BISHOP]: pos.match(/b/g).length,
24 [V.PAWN]: pos.match(/p/g).length
25 }
26 };
27 }
28
29 getPotentialPawnMoves([x, y]) {
30 let moves = super.getPotentialPawnMoves([x, y]);
31 // Add potential promotions into king
32 const color = this.turn;
33 const shift = color == "w" ? -1 : 1;
34 const lastRank = color == "w" ? 0 : V.size.x - 1;
35
36 if (x + shift == lastRank) {
37 // Normal move
38 if (this.board[x + shift][y] == V.EMPTY)
39 moves.push(
40 this.getBasicMove([x, y], [x + shift, y], { c: color, p: V.KING })
41 );
42 // Captures
43 if (
44 y > 0 &&
45 this.board[x + shift][y - 1] != V.EMPTY &&
46 this.canTake([x, y], [x + shift, y - 1])
47 ) {
48 moves.push(
49 this.getBasicMove([x, y], [x + shift, y - 1], { c: color, p: V.KING })
50 );
51 }
52 if (
53 y < V.size.y - 1 &&
54 this.board[x + shift][y + 1] != V.EMPTY &&
55 this.canTake([x, y], [x + shift, y + 1])
56 ) {
57 moves.push(
58 this.getBasicMove([x, y], [x + shift, y + 1], { c: color, p: V.KING })
59 );
60 }
61 }
62
63 return moves;
64 }
65
66 // TODO: verify this assertion
67 atLeastOneMove() {
68 return true; //always at least one possible move
69 }
70
71 underCheck() {
72 return false; //there is no check
73 }
74
75 getCheckSquares() {
76 return [];
77 }
78
79 updateVariables(move) {
80 super.updateVariables(move);
81 // Treat the promotion case: (not the capture part)
82 if (move.appear[0].p != move.vanish[0].p) {
83 this.material[move.appear[0].c][move.appear[0].p]++;
84 this.material[move.appear[0].c][V.PAWN]--;
85 }
86 if (move.vanish.length == 2 && move.appear.length == 1)
87 //capture
88 this.material[move.vanish[1].c][move.vanish[1].p]--;
89 }
90
91 unupdateVariables(move) {
92 super.unupdateVariables(move);
93 if (move.appear[0].p != move.vanish[0].p) {
94 this.material[move.appear[0].c][move.appear[0].p]--;
95 this.material[move.appear[0].c][V.PAWN]++;
96 }
97 if (move.vanish.length == 2 && move.appear.length == 1)
98 this.material[move.vanish[1].c][move.vanish[1].p]++;
99 }
100
101 getCurrentScore() {
102 if (this.atLeastOneMove()) {
103 // game not over?
104 const color = this.turn;
105 if (
106 Object.keys(this.material[color]).some(p => {
107 return this.material[color][p] == 0;
108 })
109 ) {
110 return this.turn == "w" ? "0-1" : "1-0";
111 }
112 return "*";
113 }
114
115 return this.turn == "w" ? "0-1" : "1-0"; //NOTE: currently unreachable...
116 }
117
118 evalPosition() {
119 const color = this.turn;
120 if (
121 Object.keys(this.material[color]).some(p => {
122 return this.material[color][p] == 0;
123 })
124 ) {
125 // Very negative (resp. positive) if white (reps. black) pieces set is incomplete
126 return (color == "w" ? -1 : 1) * V.INFINITY;
127 }
128 return super.evalPosition();
129 }
130 };