f7d2fa13422b189e3258bb6a923c8545d582184f
1 // NOTE: alternative implementation, probably cleaner = use only 1 board
2 class AliceRules
extends ChessRules
4 static get ALICE_PIECES()
15 static get ALICE_CODES()
29 return (Object
.keys(this.ALICE_PIECES
).includes(b
[1]) ? "Alice/" : "") + b
;
34 return ChessRules
.PIECES
.concat(Object
.keys(V
.ALICE_PIECES
));
37 setOtherVariables(fen
)
39 super.setOtherVariables(fen
);
40 const rows
= V
.ParseFen(fen
).position
.split("/");
41 if (this.kingPos
["w"][0] < 0 || this.kingPos
["b"][0] < 0)
43 // INIT_COL_XXX won't be required if Alice kings are found (means 'king moved')
44 for (let i
=0; i
<rows
.length
; i
++)
46 let k
= 0; //column index on board
47 for (let j
=0; j
<rows
[i
].length
; j
++)
49 switch (rows
[i
].charAt(j
))
52 this.kingPos
['b'] = [i
,k
];
55 this.kingPos
['w'] = [i
,k
];
58 const num
= parseInt(rows
[i
].charAt(j
));
68 // Return the (standard) color+piece notation at a square for a board
69 getSquareOccupation(i
, j
, mirrorSide
)
71 const piece
= this.getPiece(i
,j
);
72 if (mirrorSide
==1 && Object
.keys(V
.ALICE_CODES
).includes(piece
))
73 return this.board
[i
][j
];
74 else if (mirrorSide
==2 && Object
.keys(V
.ALICE_PIECES
).includes(piece
))
75 return this.getColor(i
,j
) + V
.ALICE_PIECES
[piece
];
79 // Build board of the given (mirror)side
80 getSideBoard(mirrorSide
)
82 // Build corresponding board from complete board
83 let sideBoard
= doubleArray(V
.size
.x
, V
.size
.y
, "");
84 for (let i
=0; i
<V
.size
.x
; i
++)
86 for (let j
=0; j
<V
.size
.y
; j
++)
87 sideBoard
[i
][j
] = this.getSquareOccupation(i
, j
, mirrorSide
);
92 // NOTE: castle & enPassant https://www.chessvariants.com/other.dir/alice.html
93 getPotentialMovesFrom([x
,y
], sideBoard
)
95 const pieces
= Object
.keys(V
.ALICE_CODES
);
96 const codes
= Object
.keys(V
.ALICE_PIECES
);
97 const mirrorSide
= (pieces
.includes(this.getPiece(x
,y
)) ? 1 : 2);
99 // Search valid moves on sideBoard
100 let saveBoard
= this.board
;
101 this.board
= sideBoard
|| this.getSideBoard(mirrorSide
);
102 let moves
= super.getPotentialMovesFrom([x
,y
]);
103 this.board
= saveBoard
;
105 // Finally filter impossible moves
106 let res
= moves
.filter(m
=> {
107 if (m
.appear
.length
== 2) //castle
109 // appear[i] must be an empty square on the other board
110 for (let psq
of m
.appear
)
112 if (this.getSquareOccupation(psq
.x
,psq
.y
,3-mirrorSide
) != V
.EMPTY
)
116 else if (this.board
[m
.end
.x
][m
.end
.y
] != V
.EMPTY
)
118 // Attempt to capture
119 const piece
= this.getPiece(m
.end
.x
,m
.end
.y
);
120 if ((mirrorSide
==1 && codes
.includes(piece
))
121 || (mirrorSide
==2 && pieces
.includes(piece
)))
126 // If the move is computed on board1, m.appear change for Alice pieces.
129 m
.appear
.forEach(psq
=> { //forEach: castling taken into account
130 psq
.p
= V
.ALICE_CODES
[psq
.p
]; //goto board2
133 else //move on board2: mark vanishing pieces as Alice
135 m
.vanish
.forEach(psq
=> {
136 psq
.p
= V
.ALICE_CODES
[psq
.p
];
139 // Fix en-passant captures
140 if (m
.vanish
[0].p
== V
.PAWN
&& m
.vanish
.length
== 2
141 && this.board
[m
.end
.x
][m
.end
.y
] == V
.EMPTY
)
143 m
.vanish
[1].c
= this.getOppCol(this.getColor(x
,y
));
144 // In the special case of en-passant, if
145 // - board1 takes board2 : vanish[1] --> Alice
146 // - board2 takes board1 : vanish[1] --> normal
147 let van
= m
.vanish
[1];
148 if (mirrorSide
==1 && codes
.includes(this.getPiece(van
.x
,van
.y
)))
149 van
.p
= V
.ALICE_CODES
[van
.p
];
150 else if (mirrorSide
==2 && pieces
.includes(this.getPiece(van
.x
,van
.y
)))
151 van
.p
= V
.ALICE_PIECES
[van
.p
];
160 if (moves
.length
== 0)
162 let sideBoard
= [this.getSideBoard(1), this.getSideBoard(2)];
163 return moves
.filter(m
=> { return !this.underCheck(m
, sideBoard
); });
168 const color
= this.turn
;
169 const oppCol
= this.getOppCol(color
);
170 var potentialMoves
= [];
171 let sideBoard
= [this.getSideBoard(1), this.getSideBoard(2)];
172 for (var i
=0; i
<V
.size
.x
; i
++)
174 for (var j
=0; j
<V
.size
.y
; j
++)
176 if (this.board
[i
][j
] != V
.EMPTY
&& this.getColor(i
,j
) == color
)
179 Object
.keys(V
.ALICE_CODES
).includes(this.getPiece(i
,j
))
182 Array
.prototype.push
.apply(potentialMoves
,
183 this.getPotentialMovesFrom([i
,j
], sideBoard
[mirrorSide
-1]));
187 return this.filterValid(potentialMoves
, sideBoard
);
190 // Play on sideboards [TODO: only one sideBoard required]
191 playSide(move, sideBoard
)
193 const pieces
= Object
.keys(V
.ALICE_CODES
);
194 move.vanish
.forEach(psq
=> {
195 const mirrorSide
= (pieces
.includes(psq
.p
) ? 1 : 2);
196 sideBoard
[mirrorSide
-1][psq
.x
][psq
.y
] = V
.EMPTY
;
198 move.appear
.forEach(psq
=> {
199 const mirrorSide
= (pieces
.includes(psq
.p
) ? 1 : 2);
200 const piece
= (mirrorSide
== 1 ? psq
.p : V
.ALICE_PIECES
[psq
.p
]);
201 sideBoard
[mirrorSide
-1][psq
.x
][psq
.y
] = psq
.c
+ piece
;
203 this.kingPos
[psq
.c
] = [psq
.x
,psq
.y
];
207 // Undo on sideboards
208 undoSide(move, sideBoard
)
210 const pieces
= Object
.keys(V
.ALICE_CODES
);
211 move.appear
.forEach(psq
=> {
212 const mirrorSide
= (pieces
.includes(psq
.p
) ? 1 : 2);
213 sideBoard
[mirrorSide
-1][psq
.x
][psq
.y
] = V
.EMPTY
;
215 move.vanish
.forEach(psq
=> {
216 const mirrorSide
= (pieces
.includes(psq
.p
) ? 1 : 2);
217 const piece
= (mirrorSide
== 1 ? psq
.p : V
.ALICE_PIECES
[psq
.p
]);
218 sideBoard
[mirrorSide
-1][psq
.x
][psq
.y
] = psq
.c
+ piece
;
220 this.kingPos
[psq
.c
] = [psq
.x
,psq
.y
];
224 underCheck(move, sideBoard
) //sideBoard arg always provided
226 const color
= this.turn
;
227 this.playSide(move, sideBoard
); //no need to track flags
228 const kp
= this.kingPos
[color
];
229 const mirrorSide
= (sideBoard
[0][kp
[0]][kp
[1]] != V
.EMPTY
? 1 : 2);
230 let saveBoard
= this.board
;
231 this.board
= sideBoard
[mirrorSide
-1];
232 let res
= this.isAttacked(kp
, [this.getOppCol(color
)]);
233 this.board
= saveBoard
;
234 this.undoSide(move, sideBoard
);
238 getCheckSquares(move)
241 const color
= this.turn
; //opponent
242 const pieces
= Object
.keys(V
.ALICE_CODES
);
243 const kp
= this.kingPos
[color
];
244 const mirrorSide
= (pieces
.includes(this.getPiece(kp
[0],kp
[1])) ? 1 : 2);
245 let sideBoard
= this.getSideBoard(mirrorSide
);
246 let saveBoard
= this.board
;
247 this.board
= sideBoard
;
248 let res
= this.isAttacked(this.kingPos
[color
], [this.getOppCol(color
)])
249 ? [ JSON
.parse(JSON
.stringify(this.kingPos
[color
])) ]
251 this.board
= saveBoard
;
256 updateVariables(move)
258 super.updateVariables(move); //standard king
259 const piece
= this.getPiece(move.start
.x
,move.start
.y
);
260 const c
= this.getColor(move.start
.x
,move.start
.y
);
264 this.kingPos
[c
][0] = move.appear
[0].x
;
265 this.kingPos
[c
][1] = move.appear
[0].y
;
266 this.castleFlags
[c
] = [false,false];
270 unupdateVariables(move)
272 super.unupdateVariables(move);
273 const c
= this.getColor(move.start
.x
,move.start
.y
);
274 if (this.getPiece(move.start
.x
,move.start
.y
) == "l")
275 this.kingPos
[c
] = [move.start
.x
, move.start
.y
];
280 const pieces
= Object
.keys(V
.ALICE_CODES
);
281 const color
= this.turn
;
282 const kp
= this.kingPos
[color
];
283 const mirrorSide
= (pieces
.includes(this.getPiece(kp
[0],kp
[1])) ? 1 : 2);
284 let sideBoard
= this.getSideBoard(mirrorSide
);
285 let saveBoard
= this.board
;
286 this.board
= sideBoard
;
288 if (!this.isAttacked(this.kingPos
[color
], [this.getOppCol(color
)]))
291 res
= (color
== "w" ? "0-1" : "1-0");
292 this.board
= saveBoard
;
298 return Object
.assign(
313 if (move.appear
.length
== 2 && move.appear
[0].p
== V
.KING
)
315 if (move.end
.y
< move.start
.y
)
321 const finalSquare
= V
.CoordsToSquare(move.end
);
322 const piece
= this.getPiece(move.start
.x
, move.start
.y
);
324 const captureMark
= (move.vanish
.length
> move.appear
.length
? "x" : "");
326 if (["p","s"].includes(piece
) && captureMark
.length
== 1)
327 pawnMark
= V
.GetColumn(move.start
.y
); //start column
329 // Piece or pawn movement
330 let notation
= piece
.toUpperCase() + pawnMark
+ captureMark
+ finalSquare
;
331 if (['s','p'].includes(piece
) && !['s','p'].includes(move.appear
[0].p
))
334 notation
+= "=" + move.appear
[0].p
.toUpperCase();
340 const VariantRules
= AliceRules
;