1 class AliceRules
extends ChessRules
3 static get ALICE_PIECES()
14 static get ALICE_CODES()
28 return (Object
.keys(this.ALICE_PIECES
).includes(b
[1]) ? "Alice/" : "") + b
;
33 super.initVariables(fen
);
34 const fenParts
= fen
.split(" ");
35 const position
= fenParts
[0].split("/");
36 if (this.kingPos
["w"][0] < 0 || this.kingPos
["b"][0] < 0)
38 // INIT_COL_XXX won't be used, so no need to set them for Alice kings
39 for (let i
=0; i
<position
.length
; i
++)
41 let k
= 0; //column index on board
42 for (let j
=0; j
<position
[i
].length
; j
++)
44 switch (position
[i
].charAt(j
))
47 this.kingPos
['b'] = [i
,k
];
50 this.kingPos
['w'] = [i
,k
];
53 let num
= parseInt(position
[i
].charAt(j
));
63 // Build board of the given (mirror)side
64 getSideBoard(mirrorSide
)
66 const V
= VariantRules
;
67 // Build corresponding board from complete board
68 const [sizeX
,sizeY
] = V
.size
;
69 let sideBoard
= doubleArray(sizeX
, sizeY
, "");
70 for (let i
=0; i
<sizeX
; i
++)
72 for (let j
=0; j
<sizeY
; j
++)
74 const piece
= this.getPiece(i
,j
);
75 if (mirrorSide
==1 && Object
.keys(V
.ALICE_CODES
).includes(piece
))
76 sideBoard
[i
][j
] = this.board
[i
][j
];
77 else if (mirrorSide
==2 && Object
.keys(V
.ALICE_PIECES
).includes(piece
))
78 sideBoard
[i
][j
] = this.getColor(i
,j
) + V
.ALICE_PIECES
[piece
];
84 // NOTE: castle & enPassant https://www.chessvariants.com/other.dir/alice.html
85 // --> Should be OK as is.
86 getPotentialMovesFrom([x
,y
], sideBoard
)
88 const pieces
= Object
.keys(VariantRules
.ALICE_CODES
);
89 const codes
= Object
.keys(VariantRules
.ALICE_PIECES
);
90 const mirrorSide
= (pieces
.includes(this.getPiece(x
,y
)) ? 1 : 2);
92 // Search valid moves on sideBoard
93 let saveBoard
= this.board
;
94 this.board
= sideBoard
|| this.getSideBoard(mirrorSide
);
95 let moves
= super.getPotentialMovesFrom([x
,y
]);
96 this.board
= saveBoard
;
98 // Finally filter impossible moves
99 let res
= moves
.filter(m
=> {
100 if (m
.appear
.length
== 2) //castle
102 // If appear[i] not in vanish array, then must be empty square on other board
103 m
.appear
.forEach(psq
=> {
104 if (this.board
[psq
.x
][psq
.y
] != VariantRules
.EMPTY
&&
105 ![m
.vanish
[0].y
,m
.vanish
[1].y
].includes(psq
.y
))
111 else if (this.board
[m
.end
.x
][m
.end
.y
] != VariantRules
.EMPTY
)
113 // Attempt to capture
114 const piece
= this.getPiece(m
.end
.x
,m
.end
.y
);
115 if ((mirrorSide
==1 && codes
.includes(piece
))
116 || (mirrorSide
==2 && pieces
.includes(piece
)))
121 // If the move is computed on board1, m.appear change for Alice pieces.
124 m
.appear
.forEach(psq
=> { //forEach: castling taken into account
125 psq
.p
= VariantRules
.ALICE_CODES
[psq
.p
]; //goto board2
128 else //move on board2: mark vanishing pieces as Alice
130 m
.vanish
.forEach(psq
=> {
131 psq
.p
= VariantRules
.ALICE_CODES
[psq
.p
];
134 // Fix en-passant captures
135 if (m
.vanish
.length
== 2 && this.board
[m
.end
.x
][m
.end
.y
] == VariantRules
.EMPTY
)
137 m
.vanish
[1].c
= this.getOppCol(this.getColor(x
,y
));
138 // In the special case of en-passant, if
139 // - board1 takes board2 : vanish[1] --> Alice
140 // - board2 takes board1 : vanish[1] --> normal
141 let van
= m
.vanish
[1];
142 if (mirrorSide
==1 && codes
.includes(this.getPiece(van
.x
,van
.y
)))
143 van
.p
= VariantRules
.ALICE_CODES
[van
.p
];
144 else if (mirrorSide
==2 && pieces
.includes(this.getPiece(van
.x
,van
.y
)))
145 van
.p
= VariantRules
.ALICE_PIECES
[van
.p
];
152 // NOTE: alternative implementation, recompute sideBoard's in this function
153 filterValid(moves
, sideBoard
)
155 if (moves
.length
== 0)
157 const pieces
= Object
.keys(VariantRules
.ALICE_CODES
);
158 return moves
.filter(m
=> {
159 // WARNING: for underCheck(), we need the sideBoard of the arrival world !
160 const mirrorSide
= (pieces
.includes(this.getPiece(m
.start
.x
,m
.start
.y
)) ? 2 : 1);
161 return !this.underCheck(m
, !!sideBoard
? sideBoard
[mirrorSide
-1] : null);
167 const color
= this.turn
;
168 const oppCol
= this.getOppCol(color
);
169 var potentialMoves
= [];
170 let [sizeX
,sizeY
] = VariantRules
.size
;
171 let sideBoard
= [this.getSideBoard(1), this.getSideBoard(2)];
172 for (var i
=0; i
<sizeX
; i
++)
174 for (var j
=0; j
<sizeY
; j
++)
176 if (this.board
[i
][j
] != VariantRules
.EMPTY
&& this.getColor(i
,j
) == color
)
179 (Object
.keys(VariantRules
.ALICE_CODES
).includes(this.getPiece(i
,j
)) ? 1 : 2);
180 Array
.prototype.push
.apply(potentialMoves
,
181 this.getPotentialMovesFrom([i
,j
], sideBoard
[mirrorSide
-1]));
185 return this.filterValid(potentialMoves
, sideBoard
);
188 underCheck(move, sideBoard
)
190 const color
= this.turn
;
192 const pieces
= Object
.keys(VariantRules
.ALICE_CODES
);
193 const kp
= this.kingPos
[color
];
194 const mirrorSide
= (pieces
.includes(this.getPiece(kp
[0],kp
[1])) ? 1 : 2);
195 let saveBoard
= this.board
;
196 this.board
= sideBoard
|| this.getSideBoard(mirrorSide
);
197 let res
= this.isAttacked(this.kingPos
[color
], this.getOppCol(color
));
198 this.board
= saveBoard
;
203 getCheckSquares(move)
206 const color
= this.turn
; //opponent
207 const pieces
= Object
.keys(VariantRules
.ALICE_CODES
);
208 const kp
= this.kingPos
[color
];
209 const mirrorSide
= (pieces
.includes(this.getPiece(kp
[0],kp
[1])) ? 1 : 2);
210 let sideBoard
= this.getSideBoard(mirrorSide
);
211 let saveBoard
= this.board
;
212 this.board
= sideBoard
;
213 let res
= this.isAttacked(this.kingPos
[color
], this.getOppCol(color
))
214 ? [ JSON
.parse(JSON
.stringify(this.kingPos
[color
])) ]
216 this.board
= saveBoard
;
221 updateVariables(move)
223 super.updateVariables(move); //standard king
224 const piece
= this.getPiece(move.start
.x
,move.start
.y
);
225 const c
= this.getColor(move.start
.x
,move.start
.y
);
229 this.kingPos
[c
][0] = move.appear
[0].x
;
230 this.kingPos
[c
][1] = move.appear
[0].y
;
231 this.castleFlags
[c
] = [false,false];
235 unupdateVariables(move)
237 super.unupdateVariables(move);
238 const c
= this.getColor(move.start
.x
,move.start
.y
);
239 if (this.getPiece(move.start
.x
,move.start
.y
) == "l")
240 this.kingPos
[c
] = [move.start
.x
, move.start
.y
];
245 const pieces
= Object
.keys(VariantRules
.ALICE_CODES
);
246 const color
= this.turn
;
247 const kp
= this.kingPos
[color
];
248 const mirrorSide
= (pieces
.includes(this.getPiece(kp
[0],kp
[1])) ? 1 : 2);
249 let sideBoard
= this.getSideBoard(mirrorSide
);
250 let saveBoard
= this.board
;
251 this.board
= sideBoard
;
253 if (!this.isAttacked(this.kingPos
[color
], this.getOppCol(color
)))
256 res
= (color
== "w" ? "0-1" : "1-0");
257 this.board
= saveBoard
;
261 static get VALUES() {
280 if (move.appear
.length
== 2 && move.appear
[0].p
== VariantRules
.KING
)
282 if (move.end
.y
< move.start
.y
)
289 String
.fromCharCode(97 + move.end
.y
) + (VariantRules
.size
[0]-move.end
.x
);
290 const piece
= this.getPiece(move.start
.x
, move.start
.y
);
292 const captureMark
= (move.vanish
.length
> move.appear
.length
? "x" : "");
294 if (["p","s"].includes(piece
) && captureMark
.length
== 1)
295 pawnMark
= String
.fromCharCode(97 + move.start
.y
); //start column
297 // Piece or pawn movement
298 let notation
= piece
.toUpperCase() + pawnMark
+ captureMark
+ finalSquare
;
299 if (['s','p'].includes(piece
) && !['s','p'].includes(move.appear
[0].p
))
302 notation
+= "=" + move.appear
[0].p
.toUpperCase();