1 import { ChessRules
, PiPo
, Move
} from "@/base_rules";
2 import { ArrayFun
} from "@/utils/array";
3 import { randInt
} from "@/utils/alea";
5 export const VariantRules
= class HiddenRules
extends ChessRules
{
6 static get HasFlags() {
10 static get HasEnpassant() {
14 // Analyse in Hidden mode makes no sense
15 static get CanAnalyze() {
19 // Moves are revealed only when game ends
20 static get ShowMoves() {
24 static get HIDDEN_DECODE() {
34 static get HIDDEN_CODE() {
46 return ChessRules
.PIECES
.concat(Object
.values(V
.HIDDEN_CODE
));
49 // Pieces can be hidden :)
51 const piece
= this.board
[i
][j
].charAt(1);
52 if (Object
.keys(V
.HIDDEN_DECODE
).includes(piece
))
53 return V
.HIDDEN_DECODE
[piece
];
57 // Scan board for kings positions (no castling)
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
)) {
67 this.kingPos
["b"] = [i
, k
];
71 this.kingPos
["w"] = [i
, k
];
74 const num
= parseInt(fenRows
[i
].charAt(j
));
75 if (!isNaN(num
)) k
+= num
- 1;
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]];
91 // The piece is already not supposed to be hidden:
95 getBasicMove([sx
, sy
], [ex
, ey
], tr
) {
101 c: tr
? tr
.c : this.getColor(sx
, sy
),
102 p: tr
? tr
.p : this.board
[sx
][sy
].charAt(1)
109 c: this.getColor(sx
, sy
),
110 p: this.board
[sx
][sy
].charAt(1)
115 // The opponent piece disappears if we take it
116 if (this.board
[ex
][ey
] != V
.EMPTY
) {
121 c: this.getColor(ex
, ey
),
122 p: this.board
[ex
][ey
].charAt(1)
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
];
132 // What are the king moves from square x,y ?
133 getPotentialKingMoves(sq
) {
135 return this.getSlideNJumpMoves(
137 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]),
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);
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);
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);
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);
174 // Get random square for queen
175 randIndex
= randInt(10);
176 const queenPos
= positions
[randIndex
];
177 positions
.splice(randIndex
, 1);
179 // Get random square for queen
180 randIndex
= randInt(9);
181 const kingPos
= positions
[randIndex
];
182 positions
.splice(randIndex
, 1);
184 // Pawns position are all remaining slots:
185 for (let p
of positions
)
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";
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";
209 updateVariables(move) {
210 super.updateVariables(move);
212 move.vanish
.length
>= 2 &&
213 [V
.KING
,V
.HIDDEN_CODE
[V
.KING
]].includes(move.vanish
[1].p
)
215 // We took opponent king
216 this.kingPos
[this.turn
] = [-1, -1];
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
];
230 const color
= this.turn
;
231 const kp
= this.kingPos
[color
];
234 return color
== "w" ? "0-1" : "1-0";
235 // Assume that stalemate is impossible:
240 // Just return a random move. TODO: something smarter...
241 const moves
= this.getAllValidMoves();
242 return moves
[randInt(moves
.length
)];