diff options
| author | Arne Dußin | 2021-12-04 16:50:59 +0100 |
|---|---|---|
| committer | Arne Dußin | 2021-12-04 16:50:59 +0100 |
| commit | 564df712a04cdf65529e288ab9978d8196e8cd9d (patch) | |
| tree | b1f8ea72ab6f4cceb94da32cba0ce5222da7f3f2 /src | |
| parent | 15b00050c8bd1f8792a78cf88b8840d1b32fa4cb (diff) | |
| download | aoc2021-564df712a04cdf65529e288ab9978d8196e8cd9d.tar.gz aoc2021-564df712a04cdf65529e288ab9978d8196e8cd9d.zip | |
Add solution to day 4
Diffstat (limited to 'src')
| -rw-r--r-- | src/day_4.rs | 136 | ||||
| -rw-r--r-- | src/main.rs | 2 |
2 files changed, 138 insertions, 0 deletions
diff --git a/src/day_4.rs b/src/day_4.rs new file mode 100644 index 0000000..972bd94 --- /dev/null +++ b/src/day_4.rs @@ -0,0 +1,136 @@ +use std::mem::{self, MaybeUninit}; + +const BOARD_SIZE: usize = 5; + +#[derive(Clone, Debug)] +struct Board +{ + cells: [[(u8, bool); BOARD_SIZE]; BOARD_SIZE], +} + +fn part1(numbers: &[u8], mut boards: Vec<Board>) +{ + for n in numbers { + for board in boards.iter_mut() { + board.check_off(*n); + + if board.is_bingo() { + println!( + "Solution to part 1: {}", + board.sum_non_checked() * *n as u32 + ); + return; + } + } + } +} + +fn part2(numbers: &[u8], mut boards: Vec<Board>) +{ + let mut last_board_score = 0; + for n in numbers { + for board in boards.iter_mut() { + if !board.is_bingo() { + board.check_off(*n); + + let board_score = board.sum_non_checked() * *n as u32; + if board.is_bingo() && board_score != 0 { + last_board_score = board_score; + } + } + } + } + + println!("Solution to part 2: {}", last_board_score); +} + +pub fn run(input: Vec<String>) +{ + // Read the order in which the numbers will be drawn + let numbers: Vec<u8> = input[0].split(',').map(|s| s.parse().unwrap()).collect(); + + // Turn all the remaining lines into boards, each board get's it's number of + // rows + 1 for the empty line below it, which will be ignored. + let boards: Vec<Board> = input[2..] + .chunks(BOARD_SIZE + 1) + .map(|c| Board::from_strings(c)) + .collect(); + + part1(&numbers, boards.clone()); + part2(&numbers, boards); +} + +impl Board +{ + pub fn from_strings(strings: &[String]) -> Self + { + Self { + cells: { + let mut cells: [[MaybeUninit<(u8, bool)>; BOARD_SIZE]; BOARD_SIZE] = + unsafe { MaybeUninit::uninit().assume_init() }; + + for (s, row) in strings.iter().zip(cells.iter_mut()) { + for (c, cell) in s.split_whitespace().zip(row.iter_mut()) { + cell.write((c.parse().unwrap(), false)); + } + } + + unsafe { mem::transmute::<_, [[(u8, bool); BOARD_SIZE]; BOARD_SIZE]>(cells) } + }, + } + } + + pub fn check_off(&mut self, number: u8) + { + for row in &mut self.cells { + for (n, checked) in row { + if number == *n { + *checked = true; + } + } + } + } + + pub fn is_bingo(&self) -> bool + { + /* self.is_diagonal_bingo() || */ + self.is_row_bingo() || self.is_column_bingo() + } + + fn is_diagonal_bingo(&self) -> bool + { + let top_left_to_bot_right = (0..BOARD_SIZE).all(|i| self.cells[i][i].1); + let bot_left_to_top_right = (0..BOARD_SIZE).all(|i| self.cells[i][i].1); + + top_left_to_bot_right || bot_left_to_top_right + } + + fn is_row_bingo(&self) -> bool { self.cells.iter().any(|row| row.iter().all(|c| c.1)) } + + fn is_column_bingo(&self) -> bool + { + for col in 0..BOARD_SIZE { + if (0..BOARD_SIZE).all(|i| self.cells[i][col].1) { + return true; + } + } + + false + } + + pub fn sum_non_checked(&self) -> u32 + { + self.cells + .iter() + .flatten() + .filter_map(|&(n, checked)| { + if !checked { + Some(n as u32) + } + else { + None + } + }) + .sum() + } +} diff --git a/src/main.rs b/src/main.rs index 094d48b..dcb7762 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod day_1; mod day_2; mod day_3; +mod day_4; use std::fs::File; use std::io::{BufRead, BufReader}; @@ -30,6 +31,7 @@ fn run(day: u8, input: Vec<String>) 1 => day_1::run(input), 2 => day_2::run(input), 3 => day_3::run(input), + 4 => day_4::run(input), o => panic!("Day {} is not implemented (yet)", o), } } |
