1
Fork 0
advent-of-code/source/year_2021/day_04/board.rs

96 lines
2.1 KiB
Rust
Raw Normal View History

2024-01-14 21:04:10 +00:00
//! [`Board`] code and implementation.
2021-12-04 13:15:12 +00:00
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],
2021-12-04 13:15:12 +00:00
&[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],
2021-12-04 13:15:12 +00:00
];
2024-01-14 21:04:10 +00:00
/// A single bingo board.
2021-12-04 13:15:12 +00:00
#[derive(Debug, Clone)]
pub struct Board {
2024-01-14 21:04:10 +00:00
/// Whether this board has at least one line filled.
2021-12-04 13:15:12 +00:00
pub has_won: bool,
2024-01-14 21:04:10 +00:00
/// The state of the board, with indexes determining the position and whether
/// that position has been filled.
2021-12-04 13:15:12 +00:00
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| {
2021-12-04 13:15:12 +00:00
*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(' ')
2021-12-04 13:15:12 +00:00
.filter(|s| s != &"")
.map(str::parse)
.collect::<Result<_, _>>()?;
Ok(Self::new(numbers))
}
}