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