Fix Maxima (immobilize kings too)
[vchess.git] / client / src / variants / Iceage.js
1 import { ChessRules } from "@/base_rules";
2
3 export class IceageRules extends ChessRules {
4
5 static get IgnoreRepetition() {
6 return true;
7 }
8
9 static get ICECUBE() {
10 return "cc";
11 }
12
13 static board2fen(b) {
14 if (b[0] == 'c') return 'c';
15 return ChessRules.board2fen(b);
16 }
17
18 static fen2board(f) {
19 if (f == 'c') return V.ICECUBE;
20 return ChessRules.fen2board(f);
21 }
22
23 getPpath(b) {
24 if (b[0] == 'c') return "Iceage/icecube";
25 return b;
26 }
27
28 static IsGoodPosition(position) {
29 if (position.length == 0) return false;
30 const rows = position.split("/");
31 if (rows.length != V.size.x) return false;
32 let kings = { "k": 0, "K": 0 };
33 for (let row of rows) {
34 let sumElts = 0;
35 for (let i = 0; i < row.length; i++) {
36 if (['K','k'].includes(row[i])) kings[row[i]]++;
37 if (['c'].concat(V.PIECES).includes(row[i].toLowerCase())) sumElts++;
38 else {
39 const num = parseInt(row[i], 10);
40 if (isNaN(num)) return false;
41 sumElts += num;
42 }
43 }
44 if (sumElts != V.size.y) return false;
45 }
46 if (Object.values(kings).some(v => v != 1)) return false;
47 return true;
48 }
49
50 static GenRandInitFen(options) {
51 return ChessRules.GenRandInitFen(options).replace(/8/g, "cccccccc");
52 }
53
54 play(move) {
55 const iceAgeAfterMove = (this.movesCount % 40 == 39);
56 if (iceAgeAfterMove)
57 // Next ice age after this move:
58 move.state = JSON.stringify(this.board);
59 super.play(move);
60 if (iceAgeAfterMove) {
61 for (let i=0; i<8; i++) {
62 for (let j=0; j<8; j++) {
63 if (this.board[i][j] == V.EMPTY) {
64 const surrounded = V.steps[V.ROOK].every(s => {
65 const [ii, jj] = [i + s[0], j + s[1]];
66 return (
67 !V.OnBoard(ii, jj) ||
68 ![V.EMPTY, V.ICECUBE].includes(this.board[ii][jj])
69 );
70 });
71 if (!surrounded) this.board[i][j] = V.ICECUBE;
72 }
73 else if (this.board[i][j] != V.ICECUBE) {
74 const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
75 const connected = steps.some(s => {
76 const [ii, jj] = [i + s[0], j + s[1]];
77 return (
78 V.OnBoard(ii, jj) &&
79 ![V.EMPTY, V.ICECUBE].includes(this.board[ii][jj])
80 );
81 });
82 if (!connected) this.board[i][j] = V.ICECUBE;
83 }
84 }
85 }
86 // Update king position (no need to update flags: game over)
87 const kp = this.kingPos;
88 if (this.getPiece(kp['w'][0], kp['w'][1]) != V.KING)
89 this.kingPos['w'] = [-1, -1];
90 if (this.getPiece(kp['b'][0], kp['b'][1]) != V.KING)
91 this.kingPos['b'] = [-1, -1];
92 }
93 }
94
95 undo(move) {
96 super.undo(move);
97 if (!!move.state) {
98 this.board = JSON.parse(move.state);
99 if (this.kingPos['w'][0] < 0 || this.kingPos['b'][0] < 0) {
100 for (let i=0; i<8; i++) {
101 for (let j=0; j<8; j++) {
102 if (this.board[i][j] != V.EMPTY && this.getPiece(i, j) == V.KING)
103 this.kingPos[this.getColor(i, j)] = [i, j];
104 }
105 }
106 }
107 }
108 }
109
110 getCheckSquares() {
111 if (this.kingPos[this.turn][0] < 0) return [];
112 return super.getCheckSquares();
113 }
114
115 getCurrentScore() {
116 const kingDisappear = {
117 w: this.kingPos['w'][0] < 0,
118 b: this.kingPos['b'][0] < 0
119 };
120 if (kingDisappear['w'] && kingDisappear['b']) return "1/2";
121 if (kingDisappear['w']) return "0-1";
122 if (kingDisappear['b']) return "1-0";
123 return super.getCurrentScore();
124 }
125
126 static get SEARCH_DEPTH() {
127 return 2;
128 }
129
130 evalPosition() {
131 let evaluation = 0;
132 for (let i = 0; i < V.size.x; i++) {
133 for (let j = 0; j < V.size.y; j++) {
134 if (![V.EMPTY,V.ICECUBE].includes(this.board[i][j])) {
135 const sign = this.getColor(i, j) == "w" ? 1 : -1;
136 evaluation += sign * V.VALUES[this.getPiece(i, j)];
137 }
138 }
139 }
140 return evaluation;
141 }
142
143 };