1 import { ChessRules
, PiPo
, Move
} from "@/base_rules";
2 import { ArrayFun
} from "@/utils/array";
3 import { randInt
} from "@/utils/alea";
5 export class HiddenqueenRules
extends ChessRules
{
7 // Analyse in Hiddenqueen mode makes no sense
8 static get CanAnalyze() {
12 static get HIDDEN_QUEEN() {
16 static get SomeHiddenMoves() {
21 return ChessRules
.PIECES
.concat([V
.HIDDEN_QUEEN
]);
25 const piece
= this.board
[i
][j
].charAt(1);
27 piece
!= V
.HIDDEN_QUEEN
||
28 // 'side' is used to determine what I see: a pawn or a (hidden)queen?
29 this.getColor(i
, j
) == this.side
36 getPpath(b
, color
, score
) {
37 if (b
[1] == V
.HIDDEN_QUEEN
) {
38 // Supposed to be hidden.
39 if (score
== "*" && (!color
|| color
!= b
[0]))
41 return "Hiddenqueen/" + b
[0] + "t";
46 getEpSquare(moveOrSquare
) {
47 if (!moveOrSquare
) return undefined;
48 if (typeof moveOrSquare
=== "string") {
49 const square
= moveOrSquare
;
50 if (square
== "-") return undefined;
51 return V
.SquareToCoords(square
);
53 const move = moveOrSquare
;
56 const color
= move.vanish
[0].c
;
59 Math
.abs(s
.x
- e
.x
) == 2 &&
60 ((color
== 'w' && s
.x
== 6) || (color
== 'b' && s
.x
== 1)) &&
61 [V
.PAWN
, V
.HIDDEN_QUEEN
].includes(move.vanish
[0].p
)
68 return undefined; //default
71 isValidPawnMove(move) {
72 const color
= move.vanish
[0].c
;
73 const pawnShift
= color
== "w" ? -1 : 1;
74 const startRank
= color
== "w" ? V
.size
.x
- 2 : 1;
77 move.end
.x
- move.start
.x
== pawnShift
&&
81 move.end
.y
== move.start
.y
&&
82 this.board
[move.end
.x
][move.end
.y
] == V
.EMPTY
87 Math
.abs(move.end
.y
- move.start
.y
) == 1 &&
88 this.board
[move.end
.x
][move.end
.y
] != V
.EMPTY
94 // Two-spaces initial jump
95 move.start
.x
== startRank
&&
96 move.end
.y
== move.start
.y
&&
97 move.end
.x
- move.start
.x
== 2 * pawnShift
&&
98 this.board
[move.end
.x
][move.end
.y
] == V
.EMPTY
103 getPotentialMovesFrom([x
, y
]) {
104 if (this.getPiece(x
, y
) == V
.HIDDEN_QUEEN
) {
105 const pawnMoves
= this.getPotentialPawnMoves([x
, y
]);
106 let queenMoves
= super.getPotentialQueenMoves([x
, y
]);
107 // Remove from queen moves those corresponding to a pawn move:
108 queenMoves
= queenMoves
109 .filter(m
=> !this.isValidPawnMove(m
))
110 // Hidden queen is revealed if moving like a queen:
112 m
.appear
[0].p
= V
.QUEEN
;
115 return pawnMoves
.concat(queenMoves
);
117 return super.getPotentialMovesFrom([x
, y
]);
120 getEnpassantCaptures([x
, y
], shiftX
) {
121 const Lep
= this.epSquares
.length
;
122 const epSquare
= this.epSquares
[Lep
- 1];
123 let enpassantMove
= null;
126 epSquare
.x
== x
+ shiftX
&&
127 Math
.abs(epSquare
.y
- y
) == 1
129 enpassantMove
= this.getBasicMove([x
, y
], [epSquare
.x
, epSquare
.y
]);
130 enpassantMove
.vanish
.push({
133 // Captured piece may be a hidden queen
134 p: this.board
[x
][epSquare
.y
][1],
135 c: this.getColor(x
, epSquare
.y
)
138 return !!enpassantMove
? [enpassantMove
] : [];
141 getPotentialPawnMoves([x
, y
]) {
142 const piece
= this.getPiece(x
, y
);
145 ? [V
.ROOK
, V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
]
146 : [V
.QUEEN
]; //hidden queen revealed
147 return super.getPotentialPawnMoves([x
, y
], promotions
);
150 getPossibleMovesFrom(sq
) {
151 this.side
= this.turn
;
152 return this.filterValid(this.getPotentialMovesFrom(sq
));
155 static GenRandInitFen(randomness
) {
156 let fen
= ChessRules
.GenRandInitFen(randomness
);
157 // Place hidden queens at random (always):
158 let hiddenQueenPos
= randInt(8);
159 let pawnRank
= "PPPPPPPP".split("");
160 pawnRank
[hiddenQueenPos
] = "T";
161 fen
= fen
.replace("PPPPPPPP", pawnRank
.join(""));
162 hiddenQueenPos
= randInt(8);
163 pawnRank
= "pppppppp".split("");
164 pawnRank
[hiddenQueenPos
] = "t";
165 fen
= fen
.replace("pppppppp", pawnRank
.join(""));
170 super.postPlay(move);
171 if (move.vanish
.length
== 2 && move.vanish
[1].p
== V
.KING
)
172 // We took opponent king
173 this.kingPos
[this.turn
] = [-1, -1];
178 const oppCol
= this.turn
;
179 if (this.kingPos
[oppCol
][0] < 0)
180 // Move takes opponent's king:
181 this.kingPos
[oppCol
] = [move.vanish
[1].x
, move.vanish
[1].y
];
185 if (this.kingPos
[color
][0] < 0) return false;
186 return super.underCheck(color
);
190 const color
= this.turn
;
191 if (this.kingPos
[color
][0] < 0)
193 return (color
== "w" ? "0-1" : "1-0");
194 const oldSide
= this.side
;
196 const res
= super.getCurrentScore();
201 // Search is biased, so not really needed to explore deeply
202 static get SEARCH_DEPTH() {
206 static get VALUES() {
207 return Object
.assign(
214 this.side
= this.turn
;
215 return super.getComputerMove();
219 // Not using getPiece() method because it would transform HQ into pawn:
220 if (this.board
[move.start
.x
][move.start
.y
].charAt(1) != V
.HIDDEN_QUEEN
)
221 return super.getNotation(move);
222 const finalSquare
= V
.CoordsToSquare(move.end
);
223 if (move.appear
[0].p
== V
.QUEEN
) {
226 (move.vanish
.length
> move.appear
.length
? "x" : "") +
230 // Do not reveal hidden queens playing as pawns
232 if (move.vanish
.length
== 2)
234 notation
= V
.CoordToColumn(move.start
.y
) + "x" + finalSquare
;
235 else notation
= finalSquare
;