1 import { ChessRules
} from "@/base_rules";
3 export class AmbiguousRules
extends ChessRules
{
4 static get HasFlags() {
8 setOtherVariables(fen
) {
9 super.setOtherVariables(fen
);
10 if (this.movesCount
== 0) this.subTurn
= 2;
11 else this.subTurn
= 1;
14 // Subturn 1: play a move for the opponent on the designated square.
15 // Subturn 2: play a move for me (which just indicate a square).
16 getPotentialMovesFrom([x
, y
]) {
17 const color
= this.turn
;
18 const oppCol
= V
.GetOppCol(color
);
19 if (this.subTurn
== 2) {
20 // Just play a normal move (which in fact only indicate a square)
22 super.getPotentialMovesFrom([x
, y
])
24 if (m
.vanish
.length
== 1) m
.appear
[0].p
= V
.GOAL
;
25 else m
.appear
[0].p
= V
.TARGET_CODE
[m
.vanish
[1].p
];
26 m
.appear
[0].c
= oppCol
;
32 // At subTurn == 1, play a targeted move for opponent
33 // Search for target (we could also have it in a stack...)
34 let target
= { x: -1, y: -1 };
35 outerLoop: for (let i
= 0; i
< V
.size
.x
; i
++) {
36 for (let j
= 0; j
< V
.size
.y
; j
++) {
37 if (this.board
[i
][j
] != V
.EMPTY
) {
38 const piece
= this.board
[i
][j
][1];
41 Object
.keys(V
.TARGET_DECODE
).includes(piece
)
43 target
= { x: i
, y: j
};
49 // TODO: could be more efficient than generating all moves.
51 const emptyTarget
= (this.board
[target
.x
][target
.y
][1] == V
.GOAL
);
52 if (emptyTarget
) this.board
[target
.x
][target
.y
] = V
.EMPTY
;
53 let moves
= super.getPotentialMovesFrom([x
, y
]);
55 this.board
[target
.x
][target
.y
] = color
+ V
.GOAL
;
66 return moves
.filter(m
=> m
.end
.x
== target
.x
&& m
.end
.y
== target
.y
);
69 canIplay(side
, [x
, y
]) {
70 const color
= this.getColor(x
, y
);
72 (this.subTurn
== 1 && color
!= side
) ||
73 (this.subTurn
== 2 && color
== side
)
78 if (b
[1] == V
.GOAL
|| Object
.keys(V
.TARGET_DECODE
).includes(b
[1]))
79 return "Ambiguous/" + b
;
83 // Code for empty square target
88 static get TARGET_DECODE() {
99 static get TARGET_CODE() {
110 static get PIECES() {
112 ChessRules
.PIECES
.concat(Object
.keys(V
.TARGET_DECODE
)).concat([V
.GOAL
])
116 getAllPotentialMoves() {
117 const color
= this.turn
;
118 let potentialMoves
= [];
119 for (let i
= 0; i
< V
.size
.x
; i
++) {
120 for (let j
= 0; j
< V
.size
.y
; j
++) {
122 this.board
[i
][j
] != V
.EMPTY
&&
123 this.getColor(i
, j
) == color
&&
124 this.board
[i
][j
][1] != V
.GOAL
&&
125 !(Object
.keys(V
.TARGET_DECODE
).includes(this.board
[i
][j
][1]))
127 Array
.prototype.push
.apply(
129 this.getPotentialMovesFrom([i
, j
])
134 return potentialMoves
;
138 // Since there are no checks this seems true (same as for Magnetic...)
151 // This function is only called at subTurn 1
152 const color
= V
.GetOppCol(this.turn
);
153 if (this.kingPos
[color
][0] < 0) return (color
== 'w' ? "0-1" : "1-0");
158 const c
= V
.GetOppCol(this.turn
);
159 const piece
= move.vanish
[0].p
;
160 if (piece
== V
.KING
) {
162 this.kingPos
[c
][0] = move.appear
[0].x
;
163 this.kingPos
[c
][1] = move.appear
[0].y
;
165 if (move.vanish
.length
== 2 && [V
.KING
, 'l'].includes(move.vanish
[1].p
))
166 // (My) king is captured:
167 this.kingPos
[this.turn
] = [-1, -1];
171 let kingCaptured
= false;
172 if (this.subTurn
== 1) {
174 this.epSquares
.push(this.getEpSquare(move));
175 kingCaptured
= this.kingPos
[this.turn
][0] < 0;
177 if (kingCaptured
) move.kingCaptured
= true;
178 V
.PlayOnBoard(this.board
, move);
179 if (this.subTurn
== 2 || kingCaptured
) {
180 this.turn
= V
.GetOppCol(this.turn
);
183 if (!kingCaptured
) this.subTurn
= 3 - this.subTurn
;
187 if (!move.kingCaptured
) this.subTurn
= 3 - this.subTurn
;
188 if (this.subTurn
== 2 || !!move.kingCaptured
) {
189 this.turn
= V
.GetOppCol(this.turn
);
192 V
.UndoOnBoard(this.board
, move);
193 if (this.subTurn
== 1) {
194 this.epSquares
.pop();
200 // (Potentially) Reset king(s) position
201 const c
= V
.GetOppCol(this.turn
);
202 const piece
= move.vanish
[0].p
;
203 if (piece
== V
.KING
) {
205 this.kingPos
[c
][0] = move.vanish
[0].x
;
206 this.kingPos
[c
][1] = move.vanish
[0].y
;
208 if (move.vanish
.length
== 2 && [V
.KING
, 'l'].includes(move.vanish
[1].p
))
209 // (My) king was captured:
210 this.kingPos
[this.turn
] = [move.vanish
[1].x
, move.vanish
[1].y
];
213 static GenRandInitFen(randomness
) {
215 return "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0 -";
217 let pieces
= { w: new Array(8), b: new Array(8) };
218 for (let c
of ["w", "b"]) {
219 if (c
== 'b' && randomness
== 1) {
220 pieces
['b'] = pieces
['w'];
224 // Get random squares for every piece, totally freely
225 let positions
= shuffle(ArrayFun
.range(8));
226 const composition
= ['b', 'b', 'r', 'r', 'n', 'n', 'k', 'q'];
227 const rem2
= positions
[0] % 2;
228 if (rem2
== positions
[1] % 2) {
229 // Fix bishops (on different colors)
230 for (let i
=2; i
<8; i
++) {
231 if (positions
[i
] % 2 != rem2
)
232 [positions
[1], positions
[i
]] = [positions
[i
], positions
[1]];
235 for (let i
= 0; i
< 8; i
++) pieces
[c
][positions
[i
]] = composition
[i
];
238 pieces
["b"].join("") +
239 "/pppppppp/8/8/8/8/PPPPPPPP/" +
240 pieces
["w"].join("").toUpperCase() +
241 // En-passant allowed, but no flags
247 if (this.subTurn
== 2) return "T:" + V
.CoordsToSquare(move.end
);
248 // Remove and re-add target to get a good notation:
249 const withTarget
= move.vanish
[1];
250 if (move.vanish
[1].p
== V
.GOAL
) move.vanish
.pop();
251 else move.vanish
[1].p
= V
.TARGET_DECODE
[move.vanish
[1].p
];
252 const notation
= super.getNotation(move);
253 if (move.vanish
.length
== 1) move.vanish
.push(withTarget
);
254 else move.vanish
[1].p
= V
.TARGET_CODE
[move.vanish
[1].p
];