diff --git a/rs/src/board.rs b/rs/src/board.rs index 7c82b1e..de2576d 100644 --- a/rs/src/board.rs +++ b/rs/src/board.rs @@ -47,12 +47,6 @@ impl Position { self.file.delta(delta_file)?, )) } - fn deltas_to_valid_positions(&self, deltas: &[(i8, i8)]) -> Vec { - deltas - .iter() - .filter_map(|&delta_rank_file| self.delta(delta_rank_file).ok()) - .collect() - } } #[derive(PartialEq, Eq, Hash, Clone, Copy)] @@ -173,30 +167,73 @@ pub struct Piece { pub piece_type: PieceType, } -impl Piece { - fn get_moves(&self, position: &Position) -> Vec { - let deltas = match self.piece_type { - PieceType::Pawn => self._pawn_get_move_deltas(position), - }; - position.deltas_to_valid_positions(&deltas) - } - fn get_captures(&self, position: &Position) -> Vec { - let deltas = match self.piece_type { - PieceType::Pawn => self._pawn_get_capture_deltas(), - }; - position.deltas_to_valid_positions(&deltas) - } - fn _pawn_get_move_deltas(&self, position: &Position) -> Vec<(i8, i8)> { - let direction = self.color.get_direction(); - if position.rank == self.color.get_pawn_rank() { - vec![(direction, 0), (2 * direction, 0)] - } else { - vec![(direction, 0)] +struct Ray { + unit: (i8, i8), + coefs: Option>, + source: Position, + current: u8, +} + +impl Ray { + fn new(unit: (i8, i8), coefs: Option>, source: Position) -> Self { + Ray { + unit, + coefs, + source, + current: 0, } } - fn _pawn_get_capture_deltas(&self) -> Vec<(i8, i8)> { - let direction = self.color.get_direction(); - vec![(direction, 1), (direction, -1)] +} + +impl Iterator for Ray { + type Item = Position; + fn next(&mut self) -> Option { + let (delta_unit_rank, delta_unit_file) = self.unit; + let coef = i8::try_from(match &self.coefs { + None => self.current + 1, + Some(coefs) => { + let crt_usize = self.current as usize; + if crt_usize >= coefs.len() { + return None; + } + coefs[crt_usize] + } + }) + .unwrap(); + let delta = ( + delta_unit_rank.checked_mul(coef).unwrap(), + delta_unit_file.checked_mul(coef).unwrap(), + ); + let rval = self.source.delta(delta).ok(); + self.current = self.current.wrapping_add(1); + rval + } +} + +impl Piece { + fn get_move_rays(&self, position: &Position) -> Vec { + match self.piece_type { + PieceType::Pawn => { + let direction = self.color.get_direction(); + let coefs = if position.rank == self.color.get_pawn_rank() { + vec![1, 2] + } else { + vec![1] + }; + vec![Ray::new((direction, 0), Some(coefs), position.clone())] + } + } + } + fn get_capture_rays(&self, position: &Position) -> Vec { + match self.piece_type { + PieceType::Pawn => { + let direction = self.color.get_direction(); + vec![ + Ray::new((direction, 1), Some(vec![1]), position.clone()), + Ray::new((direction, -1), Some(vec![1]), position.clone()), + ] + } + } } } @@ -214,7 +251,7 @@ impl Board { None => self.state.remove(&position), }; } - fn move_from_to( + fn relocate( &mut self, source: &Position, target: Position, @@ -240,6 +277,17 @@ impl Board { pub fn iter(&self) -> impl Iterator { self.state.iter() } + fn cut_move_ray(&self, ray: Ray) -> impl Iterator + '_ { + ray.into_iter().take_while(|position| self.get_at(position).is_none()) + } + fn find_capture(&self, ray: Ray) -> Option { + // I'm not expecting to call this if there's no piece in the position + let crt_piece = self.get_at(&ray.source).unwrap(); + ray.into_iter().find(|p| match self.get_at(p) { + None => false, + Some(piece) => piece.color != crt_piece.color, + }) + } pub fn get_legal_moves( &self, position: &Position, @@ -249,16 +297,13 @@ impl Board { Some(piece) => piece, }; let valid_moves = piece - .get_moves(position) + .get_move_rays(position) .into_iter() - .filter(|pos| self.get_at(pos).is_none()); - let valid_captures = - piece.get_captures(position).into_iter().filter(|pos| match self - .get_at(pos) - { - None => false, - Some(other_piece) => (other_piece.color != piece.color), - }); + .flat_map(|ray| self.cut_move_ray(ray)); + let valid_captures = piece + .get_capture_rays(position) + .into_iter() + .filter_map(|ray| self.find_capture(ray)); Some(valid_moves.chain(valid_captures).collect()) } pub fn make_move( @@ -270,7 +315,7 @@ impl Board { Err(()) } else { // We checked that there is a piece at source in get_legal_moves - self.move_from_to(source, target) + self.relocate(source, target) } } }