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
{
6 // Analyse in Hiddenqueen mode makes no sense
7 static get CanAnalyze() {
11 static get HIDDEN_QUEEN() {
15 static get SomeHiddenMoves() {
20 return ChessRules
.PIECES
.concat([V
.HIDDEN_QUEEN
]);
24 const piece
= this.board
[i
][j
].charAt(1);
26 piece
!= V
.HIDDEN_QUEEN
||
27 // 'side' is used to determine what I see: a pawn or a (hidden)queen?
28 this.getColor(i
, j
) == this.side
35 getPpath(b
, color
, score
) {
36 if (b
[1] == V
.HIDDEN_QUEEN
) {
37 // Supposed to be hidden.
38 if (score
== "*" && (!color
|| color
!= b
[0]))
40 return "Hiddenqueen/" + b
[0] + "t";
45 isValidPawnMove(move) {
46 const color
= move.vanish
[0].c
;
47 const pawnShift
= color
== "w" ? -1 : 1;
48 const startRank
= color
== "w" ? V
.size
.x
- 2 : 1;
51 move.end
.x
- move.start
.x
== pawnShift
&&
55 move.end
.y
== move.start
.y
&&
56 this.board
[move.end
.x
][move.end
.y
] == V
.EMPTY
61 Math
.abs(move.end
.y
- move.start
.y
) == 1 &&
62 this.board
[move.end
.x
][move.end
.y
] != V
.EMPTY
68 // Two-spaces initial jump
69 move.start
.x
== startRank
&&
70 move.end
.y
== move.start
.y
&&
71 move.end
.x
- move.start
.x
== 2 * pawnShift
&&
72 this.board
[move.end
.x
][move.end
.y
] == V
.EMPTY
77 getPotentialMovesFrom([x
, y
]) {
78 if (this.getPiece(x
, y
) == V
.HIDDEN_QUEEN
) {
79 const pawnMoves
= this.getPotentialPawnMoves([x
, y
]);
80 let queenMoves
= super.getPotentialQueenMoves([x
, y
]);
81 // Remove from queen moves those corresponding to a pawn move:
82 queenMoves
= queenMoves
83 .filter(m
=> !this.isValidPawnMove(m
))
84 // Hidden queen is revealed if moving like a queen:
86 m
.appear
[0].p
= V
.QUEEN
;
89 return pawnMoves
.concat(queenMoves
);
91 return super.getPotentialMovesFrom([x
, y
]);
94 getPotentialPawnMoves([x
, y
]) {
95 const piece
= this.getPiece(x
, y
);
98 ? [V
.ROOK
, V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
]
99 : [V
.QUEEN
]; //hidden queen revealed
100 return super.getPotentialPawnMoves([x
, y
], promotions
);
103 getPossibleMovesFrom(sq
) {
104 this.side
= this.turn
;
105 return this.filterValid(this.getPotentialMovesFrom(sq
));
108 static GenRandInitFen(randomness
) {
109 let fen
= ChessRules
.GenRandInitFen(randomness
);
110 // Place hidden queens at random (always):
111 let hiddenQueenPos
= randInt(8);
112 let pawnRank
= "PPPPPPPP".split("");
113 pawnRank
[hiddenQueenPos
] = "T";
114 fen
= fen
.replace("PPPPPPPP", pawnRank
.join(""));
115 hiddenQueenPos
= randInt(8);
116 pawnRank
= "pppppppp".split("");
117 pawnRank
[hiddenQueenPos
] = "t";
118 fen
= fen
.replace("pppppppp", pawnRank
.join(""));
123 super.postPlay(move);
124 if (move.vanish
.length
== 2 && move.vanish
[1].p
== V
.KING
)
125 // We took opponent king
126 this.kingPos
[this.turn
] = [-1, -1];
131 const oppCol
= this.turn
;
132 if (this.kingPos
[oppCol
][0] < 0)
133 // Move takes opponent's king:
134 this.kingPos
[oppCol
] = [move.vanish
[1].x
, move.vanish
[1].y
];
138 const color
= this.turn
;
139 if (this.kingPos
[color
][0] < 0)
141 return color
== "w" ? "0-1" : "1-0";
142 return super.getCurrentScore();
145 // Search is biased, so not really needed to explore deeply
146 static get SEARCH_DEPTH() {
150 static get VALUES() {
151 return Object
.assign(
158 this.side
= this.turn
;
159 return super.getComputerMove();
163 if (this.getPiece(move.start
.x
, move.start
.y
) != V
.HIDDEN_QUEEN
)
164 return super.getNotation(move);
165 const finalSquare
= V
.CoordsToSquare(move.end
);
166 if (move.appear
[0].p
== V
.QUEEN
) {
169 (move.vanish
.length
> move.appear
.length
? "x" : "") +
173 // Do not reveal hidden queens playing as pawns
175 if (move.vanish
.length
== 2)
177 notation
= V
.CoordToColumn(move.start
.y
) + "x" + finalSquare
;
178 else notation
= finalSquare
;