From ff00f498999e86bbbdd3f4a8d45445123d4828d0 Mon Sep 17 00:00:00 2001 From: Devon Sawatsky Date: Mon, 11 Aug 2025 14:35:55 +0000 Subject: [PATCH] add pawn moves :3 --- src/lib.rs | 271 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 186 insertions(+), 85 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6e8ddb7..3281090 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,6 +52,11 @@ impl BitBoard { fn value(&self) -> u32 { self.backing.count_ones() } + fn or(self, other: Self) -> Self { + Self { + backing: self.backing | other.backing, + } + } } struct Move { @@ -63,12 +68,14 @@ struct Move { pub struct Board { white_to_move: bool, + white_pawns: BitBoard, white_knights: BitBoard, white_bishops: BitBoard, white_rooks: BitBoard, white_queens: BitBoard, white_king: BitBoard, + black_pawns: BitBoard, black_knights: BitBoard, black_bishops: BitBoard, @@ -145,85 +152,179 @@ impl Board { + self.black_queens.value() * 9; white_value as i32 - black_value as i32 } + fn white_pieces(&self) -> BitBoard { + self.white_pawns + .or(self.white_knights) + .or(self.white_bishops) + .or(self.white_rooks) + .or(self.white_queens) + .or(self.white_king) + } + + fn black_pieces(&self) -> BitBoard { + self.black_pawns + .or(self.black_knights) + .or(self.black_bishops) + .or(self.black_rooks) + .or(self.black_queens) + .or(self.black_king) + } /* pub fn make_move(&mut self, algebra: &str) { - let (mover, non_mover) = self.movers_or_not(); - if algebra == "O-O" || algebra == "0-0" { - mover - .iter_mut() - .find(|lp| lp.piece == Piece::King) - .unwrap() - .file = 6; //castles kingside - mover - .iter_mut() - .find(|lp| lp.piece == Piece::Rook && lp.file == 7) - .unwrap() - .file = 5; - } else if algebra == "O-O-O" || algebra == "0-0-0" { - mover - .iter_mut() - .find(|lp| lp.piece == Piece::King) - .unwrap() - .file = 2; //castles queenside - mover - .iter_mut() - .find(|lp| lp.piece == Piece::Rook && lp.file == 0) - .unwrap() - .file = 3; - } else { - let mut move_segments = vec![]; - let mut iter = algebra.chars(); - while let Some(ch) = iter.next() { - if let Some(piece) = Piece::from_char(ch) { - move_segments.push(MoveSegment::Piece(piece)); - } else if let Some(rank) = ch.to_digit(10) { - move_segments.push(MoveSegment::File(rank as usize)); - } else if ch >= 'a' && ch <= 'h' { - move_segments.push(MoveSegment::File(ch as usize - 'a' as usize)); - } else if ch == 'x' { - move_segments.push(MoveSegment::Captures) - } else if ch == '=' - && let Some(next) = iter.next() // if given bad notation this breaks, but the notation was unparseable anyway - && let Some(piece) = Piece::from_char(next) - { - move_segments.push(MoveSegment::Promotion(piece)); - } - } - if move_segments.len() == 2 - && let MoveSegment::File(file) = move_segments[0] - && let MoveSegment::Rank(rank) = move_segments[1] - { - self.move_unambiguous(Piece::Pawn, None, None, rank, file); - } - } + let (mover, non_mover) = self.movers_or_not(); + if algebra == "O-O" || algebra == "0-0" { + mover + .iter_mut() + .find(|lp| lp.piece == Piece::King) + .unwrap() + .file = 6; //castles kingside + mover + .iter_mut() + .find(|lp| lp.piece == Piece::Rook && lp.file == 7) + .unwrap() + .file = 5; + } else if algebra == "O-O-O" || algebra == "0-0-0" { + mover + .iter_mut() + .find(|lp| lp.piece == Piece::King) + .unwrap() + .file = 2; //castles queenside + mover + .iter_mut() + .find(|lp| lp.piece == Piece::Rook && lp.file == 0) + .unwrap() + .file = 3; + } else { + let mut move_segments = vec![]; + let mut iter = algebra.chars(); + while let Some(ch) = iter.next() { + if let Some(piece) = Piece::from_char(ch) { + move_segments.push(MoveSegment::Piece(piece)); + } else if let Some(rank) = ch.to_digit(10) { + move_segments.push(MoveSegment::File(rank as usize)); + } else if ch >= 'a' && ch <= 'h' { + move_segments.push(MoveSegment::File(ch as usize - 'a' as usize)); + } else if ch == 'x' { + move_segments.push(MoveSegment::Captures) + } else if ch == '=' + && let Some(next) = iter.next() // if given bad notation this breaks, but the notation was unparseable anyway + && let Some(piece) = Piece::from_char(next) + { + move_segments.push(MoveSegment::Promotion(piece)); + } + } + if move_segments.len() == 2 + && let MoveSegment::File(file) = move_segments[0] + && let MoveSegment::Rank(rank) = move_segments[1] + { + self.move_unambiguous(Piece::Pawn, None, None, rank, file); + } + } } fn move_unambiguous( - &mut self, - piece: Piece, - source_rank: Option, - source_file: Option, - dest_rank: usize, - dest_file: usize, + &mut self, + piece: Piece, + source_rank: Option, + source_file: Option, + dest_rank: usize, + dest_file: usize, ) { - let piece_to_move = (if self.white_to_move { - &mut self.white + let piece_to_move = (if self.white_to_move { + &mut self.white + } else { + &mut self.black + }) + .iter_mut() + .filter(|lp| lp.piece == piece) + .filter(|lp| { + source_rank.is_none_or(|rank| rank == lp.rank) + && source_file.is_none_or(|file| file == lp.file) + }) + .find(|lp| { + self.valid_moves(lp.clone()) + .contains(&(dest_file, dest_rank)) + }) + .unwrap(); + + self.capture_if_possible(dest_file, dest_rank); + piece_to_move.rank = dest_rank; + piece_to_move.file = dest_file; + }*/ + fn pawn_moves(&self, file: u8, rank: u8) -> Vec<(u8, u8)> { + let white = self.white_pieces(); + let black = self.black_pieces(); + let white_moving = self.white_pawns.get_square(file, rank); + let either = white.or(black); + let mut moves = vec![]; + if white_moving { + let (open_squares, _) = self.open_squares(file, rank, Direction::North); + if (open_squares) > 0 { + moves.push((file, rank + 1)); + } + if rank == 1 && open_squares > 1 { + moves.push((file, rank + 2)); + } + if let (0, true) = self.open_squares(file, rank, Direction::Northeast) { + moves.push((file + 1, rank + 1)) + } + if let (0, true) = self.open_squares(file, rank, Direction::Northwest) { + moves.push((file - 1, rank + 1)) + } } else { - &mut self.black - }) - .iter_mut() - .filter(|lp| lp.piece == piece) - .filter(|lp| { - source_rank.is_none_or(|rank| rank == lp.rank) - && source_file.is_none_or(|file| file == lp.file) - }) - .find(|lp| { - self.valid_moves(lp.clone()) - .contains(&(dest_file, dest_rank)) - }) - .unwrap(); + let (open_squares, _) = self.open_squares(file, rank, Direction::South); + if open_squares > 0 { + moves.push((file, rank - 1)) + } + if rank == 6 && open_squares > 1 { + moves.push((file, rank - 2)) + } - self.capture_if_possible(dest_file, dest_rank); - piece_to_move.rank = dest_rank; - piece_to_move.file = dest_file; + if let (0, true) = self.open_squares(file, rank, Direction::Southeast) { + moves.push((file + 1, rank - 1)) + } + if let (0, true) = self.open_squares(file, rank, Direction::Southwest) { + moves.push((file - 1, rank - 1)) + } + } + moves + } + /// returns number of squares and whether that's a capture + fn open_squares(&self, mut file: u8, mut rank: u8, direction: Direction) -> (u8, bool) { + let white = self.white_pieces(); + let black = self.black_pieces(); + let white_playing = white.get_square(file, rank); + let mut count = 0; + loop { + match direction { + Direction::North => { + if rank == 7 { + return (count, false); + } else { + rank += 1 + } + } + Direction::Northeast => { + if rank == 7 || file == 7 { + return (count, false); + } else { + rank += 1; + file += 1; + } + } + Direction::East => todo!(), + Direction::Southeast => todo!(), + Direction::South => todo!(), + Direction::Southwest => todo!(), + Direction::West => todo!(), + Direction::Northwest => todo!(), + } + if white.get_square(file, rank) { + return (count, !white_playing); + } else if black.get_square(file, rank) { + return (count, white_playing); + } else { + count += 1; + } + } } fn valid_moves(&self, lp: &LocatedPiece) -> Vec<(usize, usize)> { let mut moves = vec![]; @@ -239,18 +340,18 @@ impl Board { moves.retain(|(file, rank)| !self.mover_is_in_check(file, rank)); moves } - fn movers_or_not(&mut self) -> (&mut Vec, &mut Vec) { - if self.white_to_move { - (&mut self.white, &mut self.black) - } else { - (&mut self.black, &mut self.white) - } - } - fn capture_if_possible(&mut self, file: usize, rank: usize) { - self.movers_or_not() - .1 - .retain(|lp| lp.rank != rank && lp.file != file) - } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +enum Direction { + North, + Northeast, + East, + Southeast, + South, + Southwest, + West, + Northwest, } #[derive(Clone, Copy, PartialEq, Eq)] -- 2.51.2