diff --git a/rs/src/board.rs b/rs/src/board.rs index 18c2a8b..02b3119 100644 --- a/rs/src/board.rs +++ b/rs/src/board.rs @@ -19,10 +19,10 @@ impl Color { Color::White => Rank::_2, } } - fn get_direction(&self) -> i8 { + fn other(&self) -> Color { match self { - Color::Black => -1, - Color::White => 1, + Color::Black => Color::White, + Color::White => Color::Black, } } } @@ -40,12 +40,15 @@ impl Position { file, } } - fn delta(&self, delta_rank_file: (i8, i8)) -> Result { - let (delta_rank, delta_file) = delta_rank_file; - Ok(Position::new( - self.rank.delta(delta_rank)?, - self.file.delta(delta_file)?, - )) + fn delta( + &self, + file_direction: &Direction, + rank_direction: &Direction, + ) -> Option { + Some(Position { + rank: self.rank.delta(rank_direction)?, + file: self.file.delta(file_direction)?, + }) } } @@ -73,33 +76,25 @@ pub enum File { H, } +enum Direction { + Incr, + Decr, + Stay, +} + pub trait GridAxis where Self: Sized, Self: Clone, { const ALL_VALUES: [Self; 8]; - fn new(index: u8) -> Result { - Ok(Self::ALL_VALUES[Self::validate_index(index)? as usize].clone()) - } - fn validate_index(index: u8) -> Result { - if index as usize >= Self::ALL_VALUES.len() { - Err(()) - } else { - Ok(index) - } - } - fn get_index(&self) -> u8; - fn delta(&self, delta: i8) -> Result { - let highest = Self::ALL_VALUES.len() as i8 - 1; - if delta > highest - || delta < -highest - || (delta < 0 && self.get_index() < delta.abs() as u8) - || (delta > 0 && self.get_index() + delta as u8 > highest as u8) - { - Err(()) - } else { - Self::new(((self.get_index() as i8) + delta) as u8) + fn incr(&self) -> Option; + fn decr(&self) -> Option; + fn delta(&self, direction: &Direction) -> Option { + match direction { + Direction::Incr => self.incr(), + Direction::Decr => self.decr(), + Direction::Stay => Some(self.clone()), } } } @@ -115,8 +110,29 @@ impl GridAxis for Rank { Rank::_7, Rank::_8, ]; - fn get_index(&self) -> u8 { - *self as u8 + fn incr(&self) -> Option { + match self { + Rank::_1 => Some(Rank::_2), + Rank::_2 => Some(Rank::_3), + Rank::_3 => Some(Rank::_4), + Rank::_4 => Some(Rank::_5), + Rank::_5 => Some(Rank::_6), + Rank::_6 => Some(Rank::_7), + Rank::_7 => Some(Rank::_8), + Rank::_8 => None, + } + } + fn decr(&self) -> Option { + match self { + Rank::_1 => None, + Rank::_2 => Some(Rank::_1), + Rank::_3 => Some(Rank::_2), + Rank::_4 => Some(Rank::_3), + Rank::_5 => Some(Rank::_4), + Rank::_6 => Some(Rank::_5), + Rank::_7 => Some(Rank::_6), + Rank::_8 => Some(Rank::_7), + } } } @@ -131,8 +147,29 @@ impl GridAxis for File { File::G, File::H, ]; - fn get_index(&self) -> u8 { - *self as u8 + fn incr(&self) -> Option { + match self { + File::A => Some(File::B), + File::B => Some(File::C), + File::C => Some(File::D), + File::D => Some(File::E), + File::E => Some(File::F), + File::F => Some(File::G), + File::G => Some(File::H), + File::H => None, + } + } + fn decr(&self) -> Option { + match self { + File::A => None, + File::B => Some(File::A), + File::C => Some(File::B), + File::D => Some(File::C), + File::E => Some(File::D), + File::F => Some(File::E), + File::G => Some(File::F), + File::H => Some(File::G), + } } } @@ -168,71 +205,59 @@ pub struct Piece { } struct Ray { - unit: (i8, i8), - coefs: Option>, - source: Position, - current: u8, + positions: Vec, } -impl Ray { - fn new(unit: (i8, i8), coefs: Option>, source: Position) -> Self { - Ray { - unit, - coefs, - source, - current: 0, +fn pawn_move_rays(position: &Position, color: &Color) -> Vec { + let direction = match color { + Color::Black => Direction::Decr, + Color::White => Direction::Incr, + }; + if position.rank == color.get_pawn_rank() { + let one = position.delta(&Direction::Stay, &direction).unwrap(); + let two = one.delta(&Direction::Stay, &direction).unwrap(); + vec![Ray { + positions: vec![one, two], + }] + } else { + if let Some(position) = position.delta(&Direction::Stay, &direction) { + vec![Ray { + positions: vec![position], + }] + } else { + vec![] } } } -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 +fn pawn_capture_rays(position: &Position, color: &Color) -> Vec { + let direction = match color { + Color::Black => Direction::Decr, + Color::White => Direction::Incr, + }; + let mut capture_rays = vec![]; + if let Some(p) = position.delta(&Direction::Incr, &direction) { + capture_rays.push(Ray { + positions: vec![p], + }); } + if let Some(p) = position.delta(&Direction::Decr, &direction) { + capture_rays.push(Ray { + positions: vec![p], + }); + } + capture_rays } 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())] - } + PieceType::Pawn => pawn_move_rays(position, &self.color), } } 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()), - ] - } + PieceType::Pawn => pawn_capture_rays(position, &self.color), } } } @@ -284,14 +309,19 @@ impl Board { self.state.iter() } fn cut_move_ray(&self, ray: Ray) -> impl Iterator + '_ { - ray.into_iter().take_while(|position| self.get_at(position).is_none()) + ray.positions + .into_iter() + .take_while(|position| self.get_at(position).is_none()) } - fn find_capture_along_ray(&self, ray: Ray) -> Option { + fn find_capture_along_ray( + &self, + ray: Ray, + captured_color: &Color, + ) -> 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) { + ray.positions.into_iter().find(|p| match self.get_at(p) { None => false, - Some(piece) => piece.color != crt_piece.color, + Some(piece) => &piece.color == captured_color, }) } pub fn find_moves( @@ -312,10 +342,9 @@ impl Board { position: &Position, ) -> Result + '_, ()> { if let Some(piece) = self.get_at(position) { - Ok(piece - .get_capture_rays(position) - .into_iter() - .filter_map(|ray| self.find_capture_along_ray(ray))) + Ok(piece.get_capture_rays(position).into_iter().filter_map( + |ray| self.find_capture_along_ray(ray, &piece.color.other()), + )) } else { Err(()) } diff --git a/rs/src/ui.rs b/rs/src/ui.rs index 5b1e552..ed6b18d 100644 --- a/rs/src/ui.rs +++ b/rs/src/ui.rs @@ -30,30 +30,70 @@ trait GridAxisIO: std::fmt::Display where Self: GridAxis, { - const ALL_CHARS: [char; 8]; - fn parse(c: char) -> Result { - let index = Self::ALL_CHARS.iter().position(|p| p == &c).ok_or(())?; - Ok(Self::ALL_VALUES[index].clone()) - } + fn parse(c: char) -> Result; } impl GridAxisIO for board::Rank { - const ALL_CHARS: [char; 8] = ['1', '2', '3', '4', '5', '6', '7', '8']; + fn parse(c: char) -> Result { + match c { + '1' => Ok(board::Rank::_1), + '2' => Ok(board::Rank::_2), + '3' => Ok(board::Rank::_3), + '4' => Ok(board::Rank::_4), + '5' => Ok(board::Rank::_5), + '6' => Ok(board::Rank::_6), + '7' => Ok(board::Rank::_7), + '8' => Ok(board::Rank::_8), + _ => Err(()), + } + } } impl std::fmt::Display for board::Rank { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", Self::ALL_CHARS[self.get_index() as usize]) + let c = match self { + board::Rank::_1 => '1', + board::Rank::_2 => '2', + board::Rank::_3 => '3', + board::Rank::_4 => '4', + board::Rank::_5 => '5', + board::Rank::_6 => '6', + board::Rank::_7 => '7', + board::Rank::_8 => '8', + }; + write!(f, "{}", c) } } impl GridAxisIO for board::File { - const ALL_CHARS: [char; 8] = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; + fn parse(c: char) -> Result { + match c { + 'a' => Ok(board::File::A), + 'b' => Ok(board::File::B), + 'c' => Ok(board::File::C), + 'd' => Ok(board::File::D), + 'e' => Ok(board::File::E), + 'f' => Ok(board::File::F), + 'g' => Ok(board::File::G), + 'h' => Ok(board::File::H), + _ => Err(()), + } + } } impl std::fmt::Display for board::File { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", Self::ALL_CHARS[self.get_index() as usize]) + let c = match self { + board::File::A => 'a', + board::File::B => 'b', + board::File::C => 'c', + board::File::D => 'd', + board::File::E => 'e', + board::File::F => 'f', + board::File::G => 'g', + board::File::H => 'h', + }; + write!(f, "{}", c) } }