From 6577bae991ffc57acc3c570f96d3bf9d3a45c445 Mon Sep 17 00:00:00 2001 From: Joseph Montanaro Date: Mon, 6 Dec 2021 16:30:10 -0800 Subject: [PATCH] day 4 part 1 (not currently working, also massively overcomplicated) --- 2021/src/day4.rs | 174 +++++++++++++++++++++++++++++++++++++++++++++++ 2021/src/main.rs | 6 +- 2 files changed, 177 insertions(+), 3 deletions(-) create mode 100644 2021/src/day4.rs diff --git a/2021/src/day4.rs b/2021/src/day4.rs new file mode 100644 index 0000000..154b33d --- /dev/null +++ b/2021/src/day4.rs @@ -0,0 +1,174 @@ +use color_eyre::eyre; +use eyre::eyre; + + +struct Ratchet + where T: Copy, + F: Fn(T) -> u8, +{ + value: Option, + getter: F, +} + +impl Ratchet + where T: Copy, + F: Fn(T) -> u8 +{ + fn new(getter: F) -> Self { + Ratchet { + value: None, + getter, + } + } + + fn inc(&mut self, other: T) { + match self.value { + Some(v) if (self.getter)(other) <= (self.getter)(v) => (), + _ => self.value = Some(other), + }; + } + + fn dec(&mut self, other: T) { + match self.value { + Some(v) if (self.getter)(other) >= (self.getter)(v) => (), + _ => self.value = Some(other), + }; + } +} + + +#[derive(Copy, Clone, Default, Debug)] +struct Square { + value: u8, + draw_time: Option, +} + + +#[derive(Copy, Clone, Default, Debug)] +struct Board { + squares: [[Square; 5]; 5], + bingo_time: Option, + bingo_value: Option +} + + +impl Board { + fn from(squares: &[Square]) -> eyre::Result { + let mut it = squares.iter(); + let mut b = Self::default(); + for row in 0..5 { + for col in 0..5 { + match it.next() { + Some(sq) => b.squares[row][col] = *sq, + None => return Err(eyre!("Not enough values to populate board")), + } + } + } + Ok(b) + } + + fn set_bingo(&mut self) { + let mut board_bingo = Ratchet::new(|sq: Square| sq.draw_time.unwrap()); // these unwraps are safe because we will only call inc() or dec() after ensuring there is a value there + let mut cols_bingo: [bool; 5] = [true; 5]; + let mut cols_last_drawn: Vec> = (0..5) + .map(|_i| Ratchet::new(|sq: Square| sq.draw_time.unwrap())) + .collect(); + // let mut cols_last_drawn: [Ratchet; 5] = [Ratchet::new(|sq: Square| sq.draw_time.unwrap()); 5]; + for row in self.squares { + let mut row_bingo = true; + let mut row_last_drawn = Ratchet::new(|sq: Square| sq.draw_time.unwrap()); + for (col, sq) in row.iter().enumerate() { + match sq.draw_time { + Some(_) => { + row_last_drawn.inc(*sq); + cols_last_drawn[col].inc(*sq); + }, + None => { + row_bingo = false; + cols_bingo[col] = false; + break; + } + } + } + + if row_bingo { + let bingo_sq = row_last_drawn.value.unwrap(); // we know there will be a value here if row_bingo is true + board_bingo.dec(bingo_sq); // + } + } + + for col in 0..5 { + if cols_bingo[col] { + let bingo_sq = cols_last_drawn[col].value.unwrap(); // similar to above + board_bingo.dec(bingo_sq); + } + } + + if let Some(sq) = board_bingo.value { + self.bingo_time = sq.draw_time; + self.bingo_value = Some(sq.value); + } + } + + fn score(&self) -> eyre::Result { + let bingo_time = match self.bingo_time { + Some(t) => t, + None => return Err(eyre!("Cannot find the score of a non-winning board")), + }; + let mut total = 0usize; + for row in self.squares { + for sq in row { + if sq.draw_time.is_some() && sq.draw_time.unwrap() > bingo_time { + total += sq.value as usize; + } + } + } + Ok(total * self.bingo_value.unwrap() as usize) + } +} + + +fn load(data: &str) -> eyre::Result> { + let mut lines = data.lines().peekable(); + let mut draws: [Option; 100] = [None; 100]; // indices are the number drawn, values are the position in which it was drawn + for (i, draw) in lines.next().unwrap().split(',').enumerate() { + let num = draw.parse::()?; + draws[num] = Some(i.try_into().unwrap()); // will panic if there are more than 256 items in this iterator, but there aren't + } + + let mut boards = Vec::new(); + let mut squares = Vec::new(); + for line in lines { + for s in line.split_whitespace() { + let value = s.parse::()?; // shadows the loop variable I guess? + let sq = Square {value, draw_time: draws[value as usize]}; + squares.push(sq); + } + if squares.len() == 25 { + boards.push(Board::from(&squares)?); + boards.last_mut().unwrap().set_bingo(); + } + } + + Ok(boards) +} + + +fn part1(boards: &[Board]) -> eyre::Result { + let winner = boards.iter() + .filter(|b| b.bingo_time.is_some()) + .min_by_key(|b| b.bingo_time.unwrap()); + + match winner { + Some(w) => Ok(*w), + None => Err(eyre!("Could not find a winning board")), + } +} + + +pub fn run(data: &str) -> eyre::Result<()> { + let boards = load(data)?; + let winner = part1(&boards)?; + println!("One: {}", winner.score()?); + Ok(()) +} diff --git a/2021/src/main.rs b/2021/src/main.rs index da91b81..19ca81a 100644 --- a/2021/src/main.rs +++ b/2021/src/main.rs @@ -4,13 +4,13 @@ use color_eyre::eyre; mod lib; use lib::load; -mod day3; +mod day4; fn main() -> eyre::Result<()> { - let data = load("data/03.txt")?; + let data = load("data/04.txt")?; let start = Instant::now(); - day3::run(&data)?; + day4::run(&data)?; let (dur, unit) = format_ns(start.elapsed().as_nanos()); println!("Completed in {}{}", dur, unit); Ok(())