From 0fb63e65e95d0476b96c35602e105c0f8af56072 Mon Sep 17 00:00:00 2001 From: David Lenfesty Date: Sat, 4 Dec 2021 12:08:50 -0700 Subject: [PATCH] Finished day 4 --- src/day2.rs | 1 + src/day4.rs | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 +++ 3 files changed, 143 insertions(+) create mode 100644 src/day4.rs diff --git a/src/day2.rs b/src/day2.rs index 63d8dd3..1e13e9c 100644 --- a/src/day2.rs +++ b/src/day2.rs @@ -1,5 +1,6 @@ struct Position { pub x: i64, + #[allow(dead_code)] pub y: i64, pub z: i64, } diff --git a/src/day4.rs b/src/day4.rs new file mode 100644 index 0000000..abc48b6 --- /dev/null +++ b/src/day4.rs @@ -0,0 +1,135 @@ +use std::convert::TryInto; + +struct BingoBoard { + board: [[u8; 5]; 5], + marked: [[bool; 5]; 5], + bingo: bool, +} + +impl BingoBoard { + fn new(board: [[u8; 5]; 5]) -> Self { + Self { + board, + marked: [[false; 5]; 5], + bingo: false, + } + } + + /// Checks to see if bingo has been achieved. + /// + /// Returns true if any row or column is fully marked. (Ignores diagonals) + fn check_bingo(&mut self) -> bool { + // Check rows + for row in self.marked { + if row.iter().all(|marked| *marked) { + self.bingo = true; + return true; + } + } + + // Check columns + for i in 0..self.marked.len() { + if self.marked.iter().map(|row| row[i]).all(|marked| marked) { + self.bingo = true; + return true; + } + } + + false + } + + fn is_bingo(&self) -> bool { + self.bingo + } + + /// Checks number for existance on board and marks off any instances of it. + fn check_number(&mut self, number: u8) { + for i in 0..self.board.len() { + for j in 0..self.board[i].len() { + if self.board[i][j] == number { + self.marked[i][j] = true; + } + } + } + } + + // Scores board based on input number + fn score(&self, number: u8) -> usize { + let mut score = 0usize; + for i in 0..self.board.len() { + for j in 0..self.board[i].len() { + if !self.marked[i][j] { + score += self.board[i][j] as usize; + } + } + } + + score * number as usize + } +} + +fn parse_input(input: String) -> (Vec, Vec) { + let mut lines = input.lines(); + + let input: Vec = lines + .next() + .unwrap() + .split(',') + .map(|s| str::parse::(s).unwrap()) + .collect(); + + // Keep building boards until we don't have any more lines to parse + let mut boards = Vec::::new(); + while let Some(_) = lines.next() { + let mut board = [[0u8; 5]; 5]; + for i in 0..board.len() { + let line: Vec = lines + .next() + .unwrap() + .split_whitespace() + .map(|s| str::parse::(s).unwrap()) + .collect(); + board[i] = line.try_into().unwrap(); + } + + boards.push(BingoBoard::new(board)); + } + + (input, boards) +} + +pub fn part1(input: String) { + let (input, mut boards) = parse_input(input); + + for call in input { + // Mark and check boards + // NOTE: making big assumption here that only one board wins + for board in &mut boards { + board.check_number(call); + + if board.check_bingo() { + println!("Final score: {}", board.score(call)); + return; + } + } + } +} + +pub fn part2(input: String) { + let (input, mut boards) = parse_input(input); + + let mut final_score = 0usize; + for call in input { + for board in &mut boards { + if !board.is_bingo() { + board.check_number(call); + + if board.check_bingo() { + final_score = board.score(call); + } + } + } + } + + println!("Last winner's score: {}", final_score); +} diff --git a/src/main.rs b/src/main.rs index 65dd063..021221d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use clap::{App, Arg}; mod day1; mod day2; mod day3; +mod day4; fn main() { let matches = App::new("AOC 2021 Code") @@ -34,6 +35,7 @@ fn main() { let input = read_input(day).unwrap(); + // TODO macro-ify match day { 1 => match part { 1 => day1::day1_p1(input), @@ -50,6 +52,11 @@ fn main() { 2 => day3::part2(input), _ => (), }, + 4 => match part { + 1 => day4::part1(input), + 2 => day4::part2(input), + _ => (), + }, _ => println!("Day {} not completed yet!", day), } }