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