jordanbray / chess

A rust library to manage chess move generation

Home Page:https://jordanbray.github.io/chess/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Removing en passant doesn't work

analog-hors opened this issue · comments

Removing en passant moves doesn't work:

fn main() {
    let board = "8/8/5k2/8/3Pp3/8/2K5/8 b - d3 0 1".parse().unwrap();
    let mut moves = chess::MoveGen::new_legal(&board);
    let en_passant = "e4d3".parse().unwrap();
    moves.remove_move(en_passant);
    assert!(moves.find(|&mv| mv == en_passant).is_none()); //Assertion fails
}

The reason is because the code for removal makes the assumption that each SquareAndBitBoard has a unique source square, as it masks out the move and then returns:

pub fn remove_move(&mut self, chess_move: ChessMove) -> bool {
for x in 0..self.moves.len() {
if self.moves[x].square == chess_move.get_source() {
self.moves[x].bitboard &= !BitBoard::from_square(chess_move.get_dest());
return true;
}
}
false
}

However, this assumption fails to hold when en passant is involved, as new SquareAndBitBoards are created for every en passant move.
for src in pieces & !pinned {
let moves = Self::pseudo_legals(src, color, *combined, mask) & check_mask;
if moves != EMPTY {
unsafe {
movelist.push_unchecked(SquareAndBitBoard::new(
src,
moves,
src.get_rank() == color.to_seventh_rank(),
));
}
}
}
if !T::IN_CHECK {
for src in pieces & pinned {
let moves = Self::pseudo_legals(src, color, *combined, mask) & line(ksq, src);
if moves != EMPTY {
unsafe {
movelist.push_unchecked(SquareAndBitBoard::new(
src,
moves,
src.get_rank() == color.to_seventh_rank(),
));
}
}
}
}
if board.en_passant().is_some() {
let ep_sq = board.en_passant().unwrap();
let rank = get_rank(ep_sq.get_rank());
let files = get_adjacent_files(ep_sq.get_file());
for src in rank & files & pieces {
let dest = ep_sq.uforward(color);
if PawnType::legal_ep_move(board, src, dest) {
unsafe {
movelist.push_unchecked(SquareAndBitBoard::new(
src,
BitBoard::from_square(dest),
false,
));
}
}
}
}

This leads to remove_move returning early and never actually removing the move.