use std::str::FromStr; use color_eyre::eyre::Error; /// A matrix of all the indexes that constitute a win. const WIN_MATRIX: &[&[usize]] = &[ // Horizontal lines &[0, 1, 2, 3, 4], &[5, 6, 7, 8, 9], &[10, 11, 12, 13, 14], &[15, 16, 17, 18, 19], &[20, 21, 22, 23, 24], // Vertical lines &[0, 5, 10, 15, 20], &[1, 6, 11, 16, 21], &[2, 7, 12, 17, 22], &[3, 8, 13, 18, 23], &[4, 9, 14, 19, 24], ]; #[derive(Debug, Clone)] pub struct Board { pub has_won: bool, pub state: Vec<(i32, bool)>, } impl Board { /// Create a new board from a set of numbers. pub fn new(numbers: Vec) -> Self { Self { has_won: false, state: numbers.into_iter().map(|number| (number, false)).collect(), } } /// Check whether a board has won. pub fn check(&self) -> bool { for indexes in WIN_MATRIX { if indexes.iter().all(|index| { *self .state .get(*index) .map(|(_, state)| state) .unwrap_or(&false) }) { return true; } } false } /// Marks a target number as true in the board's state. pub fn mark_number(&mut self, target: i32) { if let Some(entry) = self.state.iter_mut().find_map(|(number, state)| { if number == &target { Some(state) } else { None } }) { *entry = true; } } /// Returns the sum of all numbers that haven't been marked as true. pub fn sum_unmarked(self) -> i32 { self .state .into_iter() .filter_map(|(number, state)| if !state { Some(number) } else { None }) .sum() } } impl FromStr for Board { type Err = Error; fn from_str(s: &str) -> Result { let numbers = s .replace('\n', " ") .split(' ') .filter(|s| s != &"") .map(str::parse) .collect::>()?; Ok(Self::new(numbers)) } }