Commit | Line | Data |
---|---|---|
241bf8f2 BA |
1 | import { ChessRules } 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 | // Scan board for kings positions (no castling) | |
50 | scanKingsRooks(fen) { | |
51 | this.kingPos = { w: [-1, -1], b: [-1, -1] }; | |
52 | const fenRows = V.ParseFen(fen).position.split("/"); | |
53 | for (let i = 0; i < fenRows.length; i++) { | |
54 | let k = 0; //column index on board | |
55 | for (let j = 0; j < fenRows[i].length; j++) { | |
56 | switch (fenRows[i].charAt(j)) { | |
57 | case "k": | |
58 | case "l": | |
59 | this.kingPos["b"] = [i, k]; | |
60 | break; | |
61 | case "K": | |
62 | case "L": | |
63 | this.kingPos["w"] = [i, k]; | |
64 | break; | |
65 | default: { | |
66 | const num = parseInt(fenRows[i].charAt(j)); | |
67 | if (!isNaN(num)) k += num - 1; | |
68 | } | |
69 | } | |
70 | k++; | |
71 | } | |
72 | } | |
73 | } | |
74 | ||
75 | getPpath(b, color, score) { | |
76 | if (Object.keys(V.HIDDEN_DECODE).includes(b[1])) { | |
77 | // Supposed to be hidden. | |
78 | if (score == "*" && (!color || color != b[0])) | |
79 | return "Hidden/" + b[0] + "p"; | |
80 | // Else: condition OK to show the piece | |
81 | return b[0] + V.HIDDEN_DECODE[b[1]]; | |
82 | } | |
83 | // The piece is already not supposed to be hidden: | |
84 | return b; | |
85 | } | |
86 | ||
87 | //getPotentialMovesFrom: TODO: write | |
88 | ||
89 | // TODO: bishops on different colors, a1 --> h1, h2 --> a2 ? | |
90 | static GenRandInitFen() { | |
91 | let pieces = { w: new Array(8), b: new Array(8) }; | |
92 | // Shuffle pieces + pawns on two first ranks | |
93 | for (let c of ["w", "b"]) { | |
94 | let positions = ArrayFun.range(16); | |
95 | ||
96 | // Get random squares for bishops | |
97 | let randIndex = 2 * randInt(8); | |
98 | const bishop1Pos = positions[randIndex]; | |
99 | // The second bishop must be on a square of different color | |
100 | let randIndex_tmp = 2 * randInt(8) + 1; | |
101 | const bishop2Pos = positions[randIndex_tmp]; | |
102 | // Remove chosen squares | |
103 | positions.splice(Math.max(randIndex, randIndex_tmp), 1); | |
104 | positions.splice(Math.min(randIndex, randIndex_tmp), 1); | |
105 | ||
106 | // Get random squares for knights | |
107 | randIndex = randInt(14); | |
108 | const knight1Pos = positions[randIndex]; | |
109 | positions.splice(randIndex, 1); | |
110 | randIndex = randInt(13); | |
111 | const knight2Pos = positions[randIndex]; | |
112 | positions.splice(randIndex, 1); | |
113 | ||
114 | // Get random square for queen | |
115 | randIndex = randInt(12); | |
116 | const queenPos = positions[randIndex]; | |
117 | positions.splice(randIndex, 1); | |
118 | ||
119 | // Get random squares for pawns | |
120 | // TODO... | |
121 | ||
122 | // Rooks and king positions are now fixed, | |
123 | // because of the ordering rook-king-rook | |
124 | const rook1Pos = positions[0]; | |
125 | const kingPos = positions[1]; | |
126 | const rook2Pos = positions[2]; | |
127 | ||
128 | // Finally put the shuffled pieces in the board array | |
129 | pieces[c][rook1Pos] = "r"; | |
130 | pieces[c][knight1Pos] = "n"; | |
131 | pieces[c][bishop1Pos] = "b"; | |
132 | pieces[c][queenPos] = "q"; | |
133 | pieces[c][kingPos] = "k"; | |
134 | pieces[c][bishop2Pos] = "b"; | |
135 | pieces[c][knight2Pos] = "n"; | |
136 | pieces[c][rook2Pos] = "r"; | |
137 | } | |
138 | return ( | |
139 | pieces["b"].join("") + | |
140 | "/pppppppp/8/8/8/8/PPPPPPPP/" + | |
141 | pieces["w"].join("").toUpperCase() + | |
142 | " w 0" | |
143 | ); | |
144 | } | |
145 | ||
146 | getCheckSquares() { | |
147 | return []; | |
148 | } | |
149 | ||
150 | updateVariables(move) { | |
151 | super.updateVariables(move); | |
152 | if ( | |
153 | move.vanish.length >= 2 && | |
154 | [V.KING,V.HIDDEN_CODE[V.KING]].includes(move.vanish[1].p) | |
155 | ) { | |
156 | // We took opponent king | |
157 | this.kingPos[this.turn] = [-1, -1]; | |
158 | } | |
159 | } | |
160 | ||
161 | unupdateVariables(move) { | |
162 | super.unupdateVariables(move); | |
163 | const c = move.vanish[0].c; | |
164 | const oppCol = V.GetOppCol(c); | |
165 | if (this.kingPos[oppCol][0] < 0) | |
166 | // Last move took opponent's king: | |
167 | this.kingPos[oppCol] = [move.vanish[1].x, move.vanish[1].y]; | |
168 | } | |
169 | ||
170 | getCurrentScore() { | |
171 | const color = this.turn; | |
172 | const kp = this.kingPos[color]; | |
173 | if (kp[0] < 0) | |
174 | // King disappeared | |
175 | return color == "w" ? "0-1" : "1-0"; | |
176 | // Assume that stalemate is impossible: | |
177 | return "*"; | |
178 | } | |
179 | ||
180 | getComputerMove() { | |
181 | // Just return a random move. TODO: something smarter... | |
182 | const moves = this.getAllValidMoves(); | |
183 | return moves[randInt(moves.length)]; | |
184 | } | |
185 | }; |