Handle multiple winners in a day 4 turn a bit more gracefully

This commit is contained in:
Nick Krichevsky 2021-12-04 14:00:00 -05:00
parent 846b02a815
commit ce9fb3e431

View file

@ -149,11 +149,13 @@ impl BingoBoard {
} }
impl<'a> Iterator for BingoPlayer<'a> { impl<'a> Iterator for BingoPlayer<'a> {
type Item = (u8, BingoBoard); // Yields the winning call and all of the boards that won with that call
type Item = (u8, Vec<BingoBoard>);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(call) = self.game.calls.pop_front() { while let Some(call) = self.game.calls.pop_front() {
let boards = &mut self.game.boards; let boards = &mut self.game.boards;
let mut winning_board: Option<BingoBoard> = None; let mut winning_boards: Vec<BingoBoard> = vec![];
for BoardState { for BoardState {
won: board_has_won, won: board_has_won,
board, board,
@ -167,13 +169,11 @@ impl<'a> Iterator for BingoPlayer<'a> {
board.mark_n(call); board.mark_n(call);
if board.is_winner() { if board.is_winner() {
// This is a bit of a hack, but it will work given the use of the iterator in part 2. // We should mark all boards, and not return immediately, so that an early board winning
// (in production code I'd probably return _all_ boards that have won)
// If two boards win at the same time, the last one needs.
//
// We should mark all boards, though, and not return immediately, so that an early board winning
// does not ruin the winners for everyone else // does not ruin the winners for everyone else
winning_board = Some(board.clone()); //
// Also, more than one board can win in the same turn (I've seen it happen!)
winning_boards.push(board.clone());
// We could probably remove the board from the boards vec, but for debugging, this changes the // We could probably remove the board from the boards vec, but for debugging, this changes the
// indexes, which makes it difficult to follow the continuity of boards // indexes, which makes it difficult to follow the continuity of boards
@ -181,8 +181,8 @@ impl<'a> Iterator for BingoPlayer<'a> {
} }
} }
if let Some(winner) = winning_board { if !winning_boards.is_empty() {
return Some((call, winner)); return Some((call, winning_boards));
} }
} }
@ -243,6 +243,15 @@ fn part1(input: &Input) -> u32 {
let (winning_call, winning_board) = game let (winning_call, winning_board) = game
.play() .play()
.next() .next()
.map(|(winning_call, winning_boards)| {
(
winning_call,
winning_boards
.into_iter()
.next()
.expect("Got back empty vec of winners, which shouldn't ever happen"),
)
})
.expect("Puzzle produced no winner for any bingo boards"); .expect("Puzzle produced no winner for any bingo boards");
calculate_score(&winning_board, winning_call.into()) calculate_score(&winning_board, winning_call.into())
@ -253,6 +262,15 @@ fn part2(input: &Input) -> u32 {
let (winning_call, winning_board) = game let (winning_call, winning_board) = game
.play() .play()
.last() .last()
.map(|(winning_call, winning_boards)| {
(
winning_call,
winning_boards
.into_iter()
.last()
.expect("Got back empty vec of winners, which shouldn't ever happen"),
)
})
.expect("Puzzle produced no winner for any bingo boards"); .expect("Puzzle produced no winner for any bingo boards");
calculate_score(&winning_board, winning_call.into()) calculate_score(&winning_board, winning_call.into())