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