diff --git a/2022/day10/rust/src/main.rs b/2022/day10/rust/src/main.rs index d15111a..5f81431 100644 --- a/2022/day10/rust/src/main.rs +++ b/2022/day10/rust/src/main.rs @@ -1,3 +1,6 @@ +#![feature(generators)] +#![feature(generator_clone)] +#![feature(iter_from_generator)] #![warn(clippy::pedantic)] use std::{ @@ -6,9 +9,48 @@ use std::{ str::FromStr, }; +type Word = i64; + +#[derive(Debug, Clone, PartialEq, Eq)] +struct MachineState { + x: Word, +} + +impl MachineState { + const fn new() -> Self { + Self { x: 1 } + } + + fn execute(&mut self, op: MicroOp) { + match op { + MicroOp::Noop => {} + MicroOp::Addx(i) => self.x += i, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum MicroOp { + Noop, + Addx(Word), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Instruction { Noop, - Addx(i32), + Addx(Word), +} + +impl Instruction { + pub fn expand(self) -> impl Iterator { + iter::from_generator(move || match self { + Self::Noop => yield MicroOp::Noop, + Self::Addx(x) => { + yield MicroOp::Noop; + yield MicroOp::Addx(x); + } + }) + } } impl FromStr for Instruction { @@ -28,35 +70,35 @@ impl FromStr for Instruction { } fn main() { + const START: MachineState = MachineState::new(); + let mut data = String::new(); stdin().read_to_string(&mut data).unwrap(); - let values = data + let states: Vec<_> = data .lines() .map(|l| l.parse().unwrap()) - .flat_map(|i: Instruction| match i { - Instruction::Noop => vec![0], - Instruction::Addx(i) => vec![0, i], + .flat_map(Instruction::expand) + .scan(START, |state, op| { + let prev = state.clone(); + state.execute(op); + Some(prev) }) - .scan(1, |acc, i| { - *acc += i; - Some(*acc) - }); - let values = iter::once(1) - .chain(values) .enumerate() - .map(|(i, x)| (i32::try_from(i).unwrap() + 1, x)); + .map(|(i, state)| (Word::try_from(i).unwrap() + 1, state)) + .collect(); - let sum: i32 = values - .clone() + let sum: Word = states + .iter() .skip(20 - 1) .step_by(40) - .map(|(i, x)| i * x) + .map(|(i, state)| i * state.x) .sum(); println!("{:?}", sum); - let crt: Vec<_> = values - .map(|(i, x)| ((i - 1) % 40).abs_diff(x) < 2) + let crt: Vec<_> = states + .iter() + .map(|(i, state)| ((i - 1) % 40).abs_diff(state.x) < 2) .map(|x| if x { '#' } else { '.' }) .collect();