From c8e03e6d6d782031dacb5291a05304b5c83cf700 Mon Sep 17 00:00:00 2001 From: Keenan Tims Date: Sat, 6 Dec 2025 00:44:36 -0800 Subject: [PATCH] day6: state machine solution, much cleaner --- src/day6.rs | 114 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 5 deletions(-) diff --git a/src/day6.rs b/src/day6.rs index 264f7b0..7ff071e 100644 --- a/src/day6.rs +++ b/src/day6.rs @@ -1,9 +1,11 @@ use aoc_runner_derive::{aoc, aoc_generator}; use grid::Grid; use itertools::Itertools; +use misc::POW10; use std::{ fmt::{Display, Write}, iter::repeat_n, + str::FromStr, }; #[repr(u8)] @@ -22,6 +24,16 @@ impl From<&str> for Op { } } +impl From<&u8> for Op { + fn from(value: &u8) -> Self { + match value { + b'+' => Op::Add, + b'*' => Op::Mul, + c => panic!("Invalid op `{c}`"), + } + } +} + impl Display for Op { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -32,7 +44,7 @@ impl Display for Op { } impl Op { - fn f(&self, lhs: u64, rhs: u64) -> u64 { + fn f(&self, lhs: &u64, rhs: &u64) -> u64 { match self { Op::Add => lhs + rhs, Op::Mul => lhs * rhs, @@ -71,7 +83,7 @@ fn part1((grid, ops): &(Grid, Vec)) -> u64 { grid.col_iter(x as i64) .unwrap() .cloned() - .reduce(|l, r| ops[x].f(l, r)) + .reduce(|l, r| ops[x].f(&l, &r)) .unwrap() }) .sum() @@ -85,7 +97,7 @@ fn part1((grid, ops): &(Grid, Vec)) -> u64 { // .collect() // } -#[aoc_generator(day6, part2)] +#[aoc_generator(day6, part2, Spaghett)] fn parse2(input: &str) -> (Grid>, Vec) { let mut rows = input.lines().collect_vec(); let ops = rows.pop().unwrap(); @@ -126,7 +138,7 @@ fn parse2(input: &str) -> (Grid>, Vec) { (grid, ops) } -#[aoc(day6, part2)] +#[aoc(day6, part2, Spaghett)] fn part2((grid, ops): &(Grid>, Vec)) -> u64 { let mut columns = Vec::new(); for col in 0..grid.width() { @@ -151,10 +163,97 @@ fn part2((grid, ops): &(Grid>, Vec)) -> u64 { columns .iter() .enumerate() - .map(|(col, v)| v.iter().cloned().reduce(|l, r| ops[col].f(l, r)).unwrap()) + .map(|(col, v)| v.iter().cloned().reduce(|l, r| ops[col].f(&l, &r)).unwrap()) .sum::() } +#[aoc_generator(day6, part2, StateMachine)] +fn parse2_walk(input: &str) -> Grid { + Grid::from_str(input).unwrap() +} + +enum NextPos { + Advance((usize, usize)), + NewCol((usize, usize)), + Done, +} + +#[aoc(day6, part2, StateMachine)] +fn part2_walk(g: &Grid) -> u64 { + let mut accum = 0; + + // start at the bottom right + let mut pos = (g.width() - 1, g.height() - 1); + let mut digits = 0; + let mut cur_value = 0; + let mut cur_values = Vec::new(); + let mut cur_op = Op::Add; + let mut last_col = false; + + let height = g.height() - 1; + + let next_pos = |(x, y)| -> NextPos { + if y == 0 { + if x == 0 { + return NextPos::Done; + } + return NextPos::NewCol((x - 1, height)); + } + NextPos::Advance((x, y - 1)) + }; + + while let Some(cur_char) = g.get(&pos) { + match cur_char { + b'*' | b'+' => { + last_col = true; + cur_op = cur_char.into() + } + cur_char if cur_char.is_ascii_digit() => { + cur_value += (*cur_char - b'0') as u64 * POW10[digits]; + digits += 1; + } + _ => {} + } + pos = match next_pos(pos) { + NextPos::Advance(p) => p, + NextPos::NewCol(p) => { + // add the value + if cur_value != 0 { + cur_values.push(cur_value); + cur_value = 0; + } + digits = 0; + // this was a last col, so reduce and accumulate + if last_col { + accum += cur_values + .iter() + .cloned() + .reduce(|l, r| cur_op.f(&l, &r)) + .unwrap_or(0); + // clear the state + cur_values.clear(); + last_col = false; + } + p + } + NextPos::Done => { + if cur_value != 0 { + cur_values.push(cur_value); + } + // accumulate the final result + accum += cur_values + .iter() + .cloned() + .reduce(|l, r| cur_op.f(&l, &r)) + .unwrap_or(0); + return accum; + } + } + } + + unreachable!() +} + #[cfg(test)] mod tests { use super::*; @@ -173,4 +272,9 @@ mod tests { fn part2_example() { assert_eq!(part2(&parse2(EXAMPLE)), 3263827); } + + #[test] + fn part2_walk_example() { + assert_eq!(part2_walk(&parse2_walk(EXAMPLE)), 3263827); + } }