summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorArne Dußin2021-12-04 16:50:59 +0100
committerArne Dußin2021-12-04 16:50:59 +0100
commit564df712a04cdf65529e288ab9978d8196e8cd9d (patch)
treeb1f8ea72ab6f4cceb94da32cba0ce5222da7f3f2 /src
parent15b00050c8bd1f8792a78cf88b8840d1b32fa4cb (diff)
downloadaoc2021-564df712a04cdf65529e288ab9978d8196e8cd9d.tar.gz
aoc2021-564df712a04cdf65529e288ab9978d8196e8cd9d.zip
Add solution to day 4
Diffstat (limited to 'src')
-rw-r--r--src/day_4.rs136
-rw-r--r--src/main.rs2
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),
}
}