78 lines
1.6 KiB
Rust
78 lines
1.6 KiB
Rust
|
use std::str::FromStr;
|
||
|
|
||
|
use color_eyre::eyre::{eyre, Error};
|
||
|
|
||
|
use super::board::Board;
|
||
|
|
||
|
#[derive(Debug)]
|
||
|
pub struct Bingo {
|
||
|
pub boards: Vec<Board>,
|
||
|
pub numbers: Vec<i32>,
|
||
|
}
|
||
|
|
||
|
impl Bingo {
|
||
|
/// The game loop for part one.
|
||
|
///
|
||
|
/// Loops over the bingo numbers until it finds the first board that has won.
|
||
|
pub fn play_until_first_win(mut self) -> (Board, i32) {
|
||
|
for number in self.numbers {
|
||
|
for board in &mut self.boards {
|
||
|
board.mark_number(number);
|
||
|
|
||
|
if board.check() {
|
||
|
return (board.clone(), number);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unreachable!()
|
||
|
}
|
||
|
|
||
|
/// The game loop for part two.
|
||
|
///
|
||
|
/// Loops over the bingo numbers until only one board is left and then returns
|
||
|
/// that as the winner.
|
||
|
pub fn play_until_last_win(mut self) -> (Board, i32) {
|
||
|
for number in self.numbers {
|
||
|
for board in &mut self.boards {
|
||
|
board.mark_number(number);
|
||
|
board.has_won = board.check();
|
||
|
}
|
||
|
|
||
|
if self.boards.len() == 1 {
|
||
|
return (self.boards.first().unwrap().clone(), number);
|
||
|
}
|
||
|
|
||
|
self.boards = self
|
||
|
.boards
|
||
|
.into_iter()
|
||
|
.filter(|board| !board.has_won)
|
||
|
.collect();
|
||
|
}
|
||
|
|
||
|
unreachable!()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl FromStr for Bingo {
|
||
|
type Err = Error;
|
||
|
|
||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
|
let numbers = s
|
||
|
.split("\n")
|
||
|
.next()
|
||
|
.ok_or(eyre!("Didn't find bingo numbers on the first line"))?
|
||
|
.split(",")
|
||
|
.map(str::parse)
|
||
|
.collect::<Result<_, _>>()?;
|
||
|
|
||
|
let boards = s
|
||
|
.split("\n\n")
|
||
|
.skip(1)
|
||
|
.map(str::parse)
|
||
|
.collect::<Result<_, _>>()?;
|
||
|
|
||
|
Ok(Self { boards, numbers })
|
||
|
}
|
||
|
}
|