#[derive(Clone)] enum Color { Black, White, } impl Color { fn get_home_rank(&self) -> Rank { match self { Color::Black => Rank::_8, Color::White => Rank::_1, } } fn get_pawn_rank(&self) -> Rank { match self { Color::Black => Rank::_7, Color::White => Rank::_2, } } fn get_direction(&self) -> i8 { match self { Color::Black => -1, Color::White => 1, } } } #[derive(Clone)] struct Position { rank: Rank, file: File, } impl Position { fn delta(&self, delta_rank_file: (i8, i8)) -> Result { let (delta_rank, delta_file) = delta_rank_file; Ok(Position { rank: self.rank.delta(delta_rank)?, file: self.file.delta(delta_file)?, }) } } #[derive(PartialEq, Clone, Copy)] enum Rank { _1, _2, _3, _4, _5, _6, _7, _8, } #[derive(PartialEq, Clone, Copy)] enum File { A, B, C, D, E, F, G, H, } trait GridAxis where Self: Sized, Self: Clone, { const ALL_VALUES: [Self; 8]; fn new(index: u8) -> Result { return 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 { Ok(Self::new(((self.get_index() as i8) + delta) as u8)?) } } } impl GridAxis for Rank { const ALL_VALUES: [Rank; 8] = [ Rank::_1, Rank::_2, Rank::_3, Rank::_4, Rank::_5, Rank::_6, Rank::_7, Rank::_8, ]; fn get_index(&self) -> u8 { *self as u8 } } impl GridAxis for File { const ALL_VALUES: [File; 8] = [ File::A, File::B, File::C, File::D, File::E, File::F, File::G, File::H, ]; fn get_index(&self) -> u8 { *self as u8 } } #[derive(Clone)] enum PieceType { Pawn, } impl PieceType { fn initial_setup(&self) -> Vec { match &self { PieceType::Pawn => [Color::Black, Color::White] .iter() .flat_map(|color| { File::ALL_VALUES.iter().map(|&file| Piece { piece_type: self.clone(), position: Position { rank: color.get_pawn_rank(), file, }, color: color.clone(), }) }) .collect(), } } } struct Piece { position: Position, color: Color, piece_type: PieceType, } trait Movement { fn get_moves(&self) -> Vec; fn get_captures(&self) -> Vec; } impl Piece { fn get_moves(&self) -> Vec { let deltas = match self.piece_type { PieceType::Pawn => self._pawn_get_move_deltas(), }; self.deltas_to_valid_positions(&deltas) } fn get_captures(&self) -> Vec { let deltas = match self.piece_type { PieceType::Pawn => self._pawn_get_capture_deltas(), }; self.deltas_to_valid_positions(&deltas) } fn deltas_to_valid_positions( &self, deltas: &Vec<(i8, i8)>, ) -> Vec { deltas .iter() .filter_map(|&delta_rank_file| { self.position.delta(delta_rank_file).ok() }) .collect() } fn _pawn_get_move_deltas(&self) -> Vec<(i8, i8)> { let direction = self.color.get_direction(); if self.position.rank == self.color.get_pawn_rank() { vec![(1 * direction, 0), (2 * direction, 0)] } else { vec![(1 * direction, 0)] } } fn _pawn_get_capture_deltas(&self) -> Vec<(i8, i8)> { let direction = self.color.get_direction(); vec![(1 * direction, 1), (1 * direction, -1)] } } struct Board { state: [[Option; File::ALL_VALUES.len()]; Rank::ALL_VALUES.len()], } impl Board { fn set_at(&mut self, position: &Position, piece: Piece) { self.state[position.rank.get_index() as usize] [position.file.get_index() as usize] = Some(piece); } fn new() -> Board { let mut board = Board { state: Default::default(), }; for piece_type in &[PieceType::Pawn] { for piece in piece_type.initial_setup() { board.set_at(&piece.position.clone(), piece); } } board } } fn main() {}