[moves] Remove special handling of EnPassant moves
Instead of generating e.p. moves in a separate pass, check whether each capture move (left and right) targets the en passant square. If so, yield an e.p. capture otherwise just a regular capture.
This commit is contained in:
		
							parent
							
								
									bba910090c
								
							
						
					
					
						commit
						428ace13dc
					
				
					 1 changed files with 25 additions and 47 deletions
				
			
		| 
						 | 
					@ -27,7 +27,6 @@ enum MoveType {
 | 
				
			||||||
    DoublePushes,
 | 
					    DoublePushes,
 | 
				
			||||||
    LeftCaptures,
 | 
					    LeftCaptures,
 | 
				
			||||||
    RightCaptures,
 | 
					    RightCaptures,
 | 
				
			||||||
    EnPassant,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct PromotionIterator {
 | 
					struct PromotionIterator {
 | 
				
			||||||
| 
						 | 
					@ -62,10 +61,6 @@ impl PawnMoveGenerator {
 | 
				
			||||||
        let (single_pushes, double_pushes) = Self::pushes(pawns, color, empty);
 | 
					        let (single_pushes, double_pushes) = Self::pushes(pawns, color, empty);
 | 
				
			||||||
        let (left_captures, right_captures) = Self::captures(pawns, color, enemies | en_passant);
 | 
					        let (left_captures, right_captures) = Self::captures(pawns, color, enemies | en_passant);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let en_passant = en_passant & (left_captures | right_captures);
 | 
					 | 
				
			||||||
        let left_captures = left_captures & !en_passant;
 | 
					 | 
				
			||||||
        let right_captures = right_captures & !en_passant;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            color,
 | 
					            color,
 | 
				
			||||||
            single_pushes,
 | 
					            single_pushes,
 | 
				
			||||||
| 
						 | 
					@ -137,22 +132,6 @@ impl PawnMoveGenerator {
 | 
				
			||||||
                Color::White => target.neighbor(Direction::SouthWest),
 | 
					                Color::White => target.neighbor(Direction::SouthWest),
 | 
				
			||||||
                Color::Black => target.neighbor(Direction::NorthEast),
 | 
					                Color::Black => target.neighbor(Direction::NorthEast),
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            MoveType::EnPassant => match self.color {
 | 
					 | 
				
			||||||
                Color::White => {
 | 
					 | 
				
			||||||
                    if (self.en_passant & self.left_captures).is_populated() {
 | 
					 | 
				
			||||||
                        target.neighbor(Direction::SouthEast)
 | 
					 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        target.neighbor(Direction::SouthWest)
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                Color::Black => {
 | 
					 | 
				
			||||||
                    if (self.en_passant & self.left_captures).is_populated() {
 | 
					 | 
				
			||||||
                        target.neighbor(Direction::NorthWest)
 | 
					 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        target.neighbor(Direction::NorthEast)
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,7 +144,6 @@ impl PawnMoveGenerator {
 | 
				
			||||||
                MoveType::DoublePushes => self.double_pushes,
 | 
					                MoveType::DoublePushes => self.double_pushes,
 | 
				
			||||||
                MoveType::LeftCaptures => self.left_captures,
 | 
					                MoveType::LeftCaptures => self.left_captures,
 | 
				
			||||||
                MoveType::RightCaptures => self.right_captures,
 | 
					                MoveType::RightCaptures => self.right_captures,
 | 
				
			||||||
                MoveType::EnPassant => self.en_passant,
 | 
					 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.target_iterator = next_bitboard.occupied_squares_trailing();
 | 
					            self.target_iterator = next_bitboard.occupied_squares_trailing();
 | 
				
			||||||
| 
						 | 
					@ -229,12 +207,16 @@ impl std::iter::Iterator for PawnMoveGenerator {
 | 
				
			||||||
                MoveType::DoublePushes => Some(GeneratedMove {
 | 
					                MoveType::DoublePushes => Some(GeneratedMove {
 | 
				
			||||||
                    ply: Move::double_push(origin, target),
 | 
					                    ply: Move::double_push(origin, target),
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
                MoveType::LeftCaptures | MoveType::RightCaptures => Some(GeneratedMove {
 | 
					                MoveType::LeftCaptures | MoveType::RightCaptures => {
 | 
				
			||||||
                    ply: Move::capture(origin, target),
 | 
					                    let target_bitboard: BitBoard = target.into();
 | 
				
			||||||
                }),
 | 
					                    Some(GeneratedMove {
 | 
				
			||||||
                MoveType::EnPassant => Some(GeneratedMove {
 | 
					                        ply: if (target_bitboard & self.en_passant).is_populated() {
 | 
				
			||||||
                    ply: Move::en_passant_capture(origin, target),
 | 
					                            Move::en_passant_capture(origin, target)
 | 
				
			||||||
                }),
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            Move::capture(origin, target)
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else if self.next_move_type().is_some() {
 | 
					        } else if self.next_move_type().is_some() {
 | 
				
			||||||
            self.next()
 | 
					            self.next()
 | 
				
			||||||
| 
						 | 
					@ -252,8 +234,7 @@ impl MoveType {
 | 
				
			||||||
            MoveType::SinglePushes => Some(MoveType::DoublePushes),
 | 
					            MoveType::SinglePushes => Some(MoveType::DoublePushes),
 | 
				
			||||||
            MoveType::DoublePushes => Some(MoveType::LeftCaptures),
 | 
					            MoveType::DoublePushes => Some(MoveType::LeftCaptures),
 | 
				
			||||||
            MoveType::LeftCaptures => Some(MoveType::RightCaptures),
 | 
					            MoveType::LeftCaptures => Some(MoveType::RightCaptures),
 | 
				
			||||||
            MoveType::RightCaptures => Some(MoveType::EnPassant),
 | 
					            MoveType::RightCaptures => None,
 | 
				
			||||||
            MoveType::EnPassant => None,
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -261,8 +242,8 @@ impl MoveType {
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use crate::{assert_move_list, assert_move_list_does_not_contain, ply, Move};
 | 
					    use crate::{assert_move_list, assert_move_list_contains, assert_move_list_does_not_contain, ply, Move};
 | 
				
			||||||
    use chessfriend_board::test_board;
 | 
					    use chessfriend_board::{fen::FromFenStr, test_board};
 | 
				
			||||||
    use chessfriend_core::{Color, Square};
 | 
					    use chessfriend_core::{Color, Square};
 | 
				
			||||||
    use std::collections::HashSet;
 | 
					    use std::collections::HashSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -370,20 +351,8 @@ mod tests {
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn black_d5_left_captures() {
 | 
					    fn black_d5_left_captures() {
 | 
				
			||||||
        let black_captures_board = test_board!(Black Pawn on D5, White Queen on E4);
 | 
					        let black_captures_board = test_board!(Black Pawn on D5, White Queen on E4);
 | 
				
			||||||
        let generated_moves: HashSet<GeneratedMove> =
 | 
					        let generated_moves = PawnMoveGenerator::new(&black_captures_board, Some(Color::Black));
 | 
				
			||||||
            PawnMoveGenerator::new(&black_captures_board, Some(Color::Black)).collect();
 | 
					        assert_move_list!(generated_moves, [ply!(D5 x E4), ply!(D5 - D4),]);
 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            generated_moves,
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                GeneratedMove {
 | 
					 | 
				
			||||||
                    ply: Move::capture(Square::D5, Square::E4)
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                GeneratedMove {
 | 
					 | 
				
			||||||
                    ply: Move::quiet(Square::D5, Square::D4)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
            .into()
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
| 
						 | 
					@ -527,7 +496,7 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let generated_moves = PawnMoveGenerator::new(&board, None);
 | 
					        let generated_moves = PawnMoveGenerator::new(&board, None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_move_list!(generated_moves, [ply!(E5 - E6), ply!(E5 x F6 e.p.),]);
 | 
					        assert_move_list!(generated_moves, [ply!(E5 - E6), ply!(E5 x F6 e.p.)]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
| 
						 | 
					@ -556,4 +525,13 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_move_list_does_not_contain!(generated_moves, [ply!(B4 x A3 e.p.)]);
 | 
					        assert_move_list_does_not_contain!(generated_moves, [ply!(B4 x A3 e.p.)]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn black_en_passant_check() {
 | 
				
			||||||
 | 
					        let board = Board::from_fen_str("8/8/8/2k5/2pP4/8/B7/4K3 b - d3 0 3").expect("invalid fen");
 | 
				
			||||||
 | 
					        println!("{}", board.display());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let generated_moves: HashSet<_> = PawnMoveGenerator::new(&board, None).collect();
 | 
				
			||||||
 | 
					        assert_move_list_contains!(generated_moves, [ply!(C4 x D3 e.p.)]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue