90 lines
1.8 KiB
Rust
90 lines
1.8 KiB
Rust
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<i32>) -> 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<Self, Self::Err> {
|
|
let numbers = s
|
|
.replace('\n', " ")
|
|
.split(' ')
|
|
.filter(|s| s != &"")
|
|
.map(str::parse)
|
|
.collect::<Result<_, _>>()?;
|
|
|
|
Ok(Self::new(numbers))
|
|
}
|
|
}
|