Draft Ball variant + some fixes, enhancements and code cleaning
[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 scanKings() {}
28
29 setOtherVariables(fen) {
30 super.setOtherVariables(fen);
31 const pos = V.ParseFen(fen).position;
32 // NOTE: no need for safety "|| []", because each piece type must be present
33 // (otherwise game is already over!)
34 this.material = {
35 w: {
36 [V.KING]: pos.match(/K/g).length,
37 [V.QUEEN]: pos.match(/Q/g).length,
38 [V.ROOK]: pos.match(/R/g).length,
39 [V.KNIGHT]: pos.match(/N/g).length,
40 [V.BISHOP]: pos.match(/B/g).length,
41 [V.PAWN]: pos.match(/P/g).length
42 },
43 b: {
44 [V.KING]: pos.match(/k/g).length,
45 [V.QUEEN]: pos.match(/q/g).length,
46 [V.ROOK]: pos.match(/r/g).length,
47 [V.KNIGHT]: pos.match(/n/g).length,
48 [V.BISHOP]: pos.match(/b/g).length,
49 [V.PAWN]: pos.match(/p/g).length
50 }
51 };
52 }
53
54 // TODO: verify this assertion
55 atLeastOneMove() {
56 return true; //always at least one possible move
57 }
58
59 filterValid(moves) {
60 return moves; //there is no check
61 }
62
63 getCheckSquares() {
64 return [];
65 }
66
67 postPlay(move) {
68 super.postPlay(move);
69 // Treat the promotion case: (not the capture part)
70 if (move.appear[0].p != move.vanish[0].p) {
71 this.material[move.appear[0].c][move.appear[0].p]++;
72 this.material[move.appear[0].c][V.PAWN]--;
73 }
74 if (move.vanish.length == 2 && move.appear.length == 1)
75 //capture
76 this.material[move.vanish[1].c][move.vanish[1].p]--;
77 }
78
79 postUndo(move) {
80 super.postUndo(move);
81 if (move.appear[0].p != move.vanish[0].p) {
82 this.material[move.appear[0].c][move.appear[0].p]--;
83 this.material[move.appear[0].c][V.PAWN]++;
84 }
85 if (move.vanish.length == 2 && move.appear.length == 1)
86 this.material[move.vanish[1].c][move.vanish[1].p]++;
87 }
88
89 getCurrentScore() {
90 if (this.atLeastOneMove()) {
91 // Game not over?
92 const color = this.turn;
93 if (
94 Object.keys(this.material[color]).some(p => {
95 return this.material[color][p] == 0;
96 })
97 ) {
98 return this.turn == "w" ? "0-1" : "1-0";
99 }
100 return "*";
101 }
102 return this.turn == "w" ? "0-1" : "1-0"; //NOTE: currently unreachable...
103 }
104
105 evalPosition() {
106 const color = this.turn;
107 if (
108 Object.keys(this.material[color]).some(p => {
109 return this.material[color][p] == 0;
110 })
111 ) {
112 // Very negative (resp. positive) if white (reps. black) pieces set is incomplete
113 return (color == "w" ? -1 : 1) * V.INFINITY;
114 }
115 return super.evalPosition();
116 }
117 };