Fixes about display
[vchess.git] / client / src / variants / Hidden.js
1 import { ChessRules, PiPo, Move } from "@/base_rules";
2 import { ArrayFun } from "@/utils/array";
3 import { randInt } from "@/utils/alea";
4
5 export const VariantRules = class HiddenRules extends ChessRules {
6 static get HasFlags() {
7 return false;
8 }
9
10 static get HasEnpassant() {
11 return false;
12 }
13
14 // Analyse in Hidden mode makes no sense
15 static get CanAnalyze() {
16 return false;
17 }
18
19 // Moves are revealed only when game ends
20 static get ShowMoves() {
21 return "none";
22 }
23
24 static get HIDDEN_DECODE() {
25 return {
26 s: "p",
27 t: "q",
28 u: "r",
29 c: "b",
30 o: "n",
31 l: "k"
32 };
33 }
34 static get HIDDEN_CODE() {
35 return {
36 p: "s",
37 q: "t",
38 r: "u",
39 b: "c",
40 n: "o",
41 k: "l"
42 };
43 }
44
45 static get PIECES() {
46 return ChessRules.PIECES.concat(Object.values(V.HIDDEN_CODE));
47 }
48
49 // Pieces can be hidden :)
50 getPiece(i, j) {
51 const piece = this.board[i][j].charAt(1);
52 if (Object.keys(V.HIDDEN_DECODE).includes(piece))
53 return V.HIDDEN_DECODE[piece];
54 return piece;
55 }
56
57 // Scan board for kings positions (no castling)
58 scanKingsRooks(fen) {
59 this.kingPos = { w: [-1, -1], b: [-1, -1] };
60 const fenRows = V.ParseFen(fen).position.split("/");
61 for (let i = 0; i < fenRows.length; i++) {
62 let k = 0; //column index on board
63 for (let j = 0; j < fenRows[i].length; j++) {
64 switch (fenRows[i].charAt(j)) {
65 case "k":
66 case "l":
67 this.kingPos["b"] = [i, k];
68 break;
69 case "K":
70 case "L":
71 this.kingPos["w"] = [i, k];
72 break;
73 default: {
74 const num = parseInt(fenRows[i].charAt(j));
75 if (!isNaN(num)) k += num - 1;
76 }
77 }
78 k++;
79 }
80 }
81 }
82
83 getPpath(b, color, score) {
84 if (Object.keys(V.HIDDEN_DECODE).includes(b[1])) {
85 // Supposed to be hidden.
86 if (score == "*" && (!color || color != b[0]))
87 return "Hidden/" + b[0] + "p";
88 // Else: condition OK to show the piece
89 return b[0] + V.HIDDEN_DECODE[b[1]];
90 }
91 // The piece is already not supposed to be hidden:
92 return b;
93 }
94
95 getBasicMove([sx, sy], [ex, ey], tr) {
96 let mv = new Move({
97 appear: [
98 new PiPo({
99 x: ex,
100 y: ey,
101 c: tr ? tr.c : this.getColor(sx, sy),
102 p: tr ? tr.p : this.board[sx][sy].charAt(1)
103 })
104 ],
105 vanish: [
106 new PiPo({
107 x: sx,
108 y: sy,
109 c: this.getColor(sx, sy),
110 p: this.board[sx][sy].charAt(1)
111 })
112 ]
113 });
114
115 // The opponent piece disappears if we take it
116 if (this.board[ex][ey] != V.EMPTY) {
117 mv.vanish.push(
118 new PiPo({
119 x: ex,
120 y: ey,
121 c: this.getColor(ex, ey),
122 p: this.board[ex][ey].charAt(1)
123 })
124 );
125 // Pieces are revealed when they capture
126 if (Object.keys(V.HIDDEN_DECODE).includes(mv.appear[0].p))
127 mv.appear[0].p = V.HIDDEN_DECODE[mv.appear[0].p];
128 }
129 return mv;
130 }
131
132 // What are the king moves from square x,y ?
133 getPotentialKingMoves(sq) {
134 // No castling:
135 return this.getSlideNJumpMoves(
136 sq,
137 V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
138 "oneStep"
139 );
140 }
141
142 static GenRandInitFen() {
143 let pieces = { w: new Array(8), b: new Array(8) };
144 // Shuffle pieces + pawns on two first ranks
145 for (let c of ["w", "b"]) {
146 let positions = ArrayFun.range(16);
147
148 // Get random squares for bishops
149 let randIndex = 2 * randInt(8);
150 const bishop1Pos = positions[randIndex];
151 // The second bishop must be on a square of different color
152 let randIndex_tmp = 2 * randInt(8) + 1;
153 const bishop2Pos = positions[randIndex_tmp];
154 // Remove chosen squares
155 positions.splice(Math.max(randIndex, randIndex_tmp), 1);
156 positions.splice(Math.min(randIndex, randIndex_tmp), 1);
157
158 // Get random squares for knights
159 randIndex = randInt(14);
160 const knight1Pos = positions[randIndex];
161 positions.splice(randIndex, 1);
162 randIndex = randInt(13);
163 const knight2Pos = positions[randIndex];
164 positions.splice(randIndex, 1);
165
166 // Get random squares for rooks
167 randIndex = randInt(12);
168 const rook1Pos = positions[randIndex];
169 positions.splice(randIndex, 1);
170 randIndex = randInt(11);
171 const rook2Pos = positions[randIndex];
172 positions.splice(randIndex, 1);
173
174 // Get random square for queen
175 randIndex = randInt(10);
176 const queenPos = positions[randIndex];
177 positions.splice(randIndex, 1);
178
179 // Get random square for queen
180 randIndex = randInt(9);
181 const kingPos = positions[randIndex];
182 positions.splice(randIndex, 1);
183
184 // Pawns position are all remaining slots:
185 for (let p of positions)
186 pieces[c][p] = "s";
187
188 // Finally put the shuffled pieces in the board array
189 pieces[c][rook1Pos] = "u";
190 pieces[c][knight1Pos] = "o";
191 pieces[c][bishop1Pos] = "c";
192 pieces[c][queenPos] = "t";
193 pieces[c][kingPos] = "l";
194 pieces[c][bishop2Pos] = "c";
195 pieces[c][knight2Pos] = "o";
196 pieces[c][rook2Pos] = "u";
197 }
198 let upFen = pieces["b"].join("");
199 upFen = upFen.substr(0,8) + "/" + upFen.substr(8);
200 let downFen = pieces["b"].join("").toUpperCase();
201 downFen = downFen.substr(0,8) + "/" + downFen.substr(8);
202 return upFen + "/8/8/8/8/" + downFen + " w 0";
203 }
204
205 getCheckSquares() {
206 return [];
207 }
208
209 updateVariables(move) {
210 super.updateVariables(move);
211 if (
212 move.vanish.length >= 2 &&
213 [V.KING,V.HIDDEN_CODE[V.KING]].includes(move.vanish[1].p)
214 ) {
215 // We took opponent king
216 this.kingPos[this.turn] = [-1, -1];
217 }
218 }
219
220 unupdateVariables(move) {
221 super.unupdateVariables(move);
222 const c = move.vanish[0].c;
223 const oppCol = V.GetOppCol(c);
224 if (this.kingPos[oppCol][0] < 0)
225 // Last move took opponent's king:
226 this.kingPos[oppCol] = [move.vanish[1].x, move.vanish[1].y];
227 }
228
229 getCurrentScore() {
230 const color = this.turn;
231 const kp = this.kingPos[color];
232 if (kp[0] < 0)
233 // King disappeared
234 return color == "w" ? "0-1" : "1-0";
235 // Assume that stalemate is impossible:
236 return "*";
237 }
238
239 getComputerMove() {
240 // Just return a random move. TODO: something smarter...
241 const moves = this.getAllValidMoves();
242 return moves[randInt(moves.length)];
243 }
244 };