day 4 part 1 (not currently working, also massively overcomplicated)

This commit is contained in:
Joseph Montanaro 2021-12-06 16:30:10 -08:00
parent c55a721067
commit 6577bae991
2 changed files with 177 additions and 3 deletions

174
2021/src/day4.rs Normal file
View File

@ -0,0 +1,174 @@
use color_eyre::eyre;
use eyre::eyre;
struct Ratchet<T, F>
where T: Copy,
F: Fn(T) -> u8,
{
value: Option<T>,
getter: F,
}
impl<T, F> Ratchet<T, F>
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<u8>,
}
#[derive(Copy, Clone, Default, Debug)]
struct Board {
squares: [[Square; 5]; 5],
bingo_time: Option<u8>,
bingo_value: Option<u8>
}
impl Board {
fn from(squares: &[Square]) -> eyre::Result<Self> {
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<Ratchet<Square, _>> = (0..5)
.map(|_i| Ratchet::new(|sq: Square| sq.draw_time.unwrap()))
.collect();
// let mut cols_last_drawn: [Ratchet<Square, _>; 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<usize> {
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<Vec<Board>> {
let mut lines = data.lines().peekable();
let mut draws: [Option<u8>; 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::<usize>()?;
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::<u8>()?; // 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<Board> {
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(())
}

View File

@ -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(())