use nom::{ bytes::complete::tag, character::complete::{i32, line_ending}, combinator::map, multi::{many0, separated_list1}, sequence::{pair, tuple}, IResult, }; use std::fs; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_10.txt")?; let program = Program::parser(&input).unwrap().1; let result = program.process(); dbg!(result.sum_of_signal_strengths(&[20, 60, 100, 140, 180, 220])); for y in 0..6 { for x in 0..40 { if result.pixel_should_activate(x, y) { print!("#"); } else { print!("."); } } println!(); } Ok(()) } #[derive(Debug)] struct Program(Vec); #[derive(Debug, Default)] struct ProgramResult(Vec); #[derive(Debug, Clone)] struct TimeSequence { time: u32, value: i32, } impl Program { fn parser(input: &str) -> IResult<&str, Self> { map(separated_list1(line_ending, TimeSequence::parser), Program)(input) } fn process(&self) -> ProgramResult { let mut result = ProgramResult::default(); let mut current_state = TimeSequence { time: 1, value: 1 }; result.0.push(current_state.clone()); for next_step in &self.0 { current_state.time += next_step.time; current_state.value += next_step.value; result.0.push(current_state.clone()); } result } } impl TimeSequence { fn parser(input: &str) -> IResult<&str, Self> { map( tuple((many0(pair(tag("noop"), line_ending)), tag("addx "), i32)), |(noops, _, value)| TimeSequence { time: noops.len() as u32 + 2, value, }, )(input) } } impl ProgramResult { fn value_at(&self, time: u32) -> i32 { self.0 .iter() .filter(|t| t.time <= time) .map(|t| t.value) .last() .unwrap_or(0) } fn signal_strength_at(&self, time: u32) -> i32 { let value = self.value_at(time); value * time as i32 } fn sum_of_signal_strengths(&self, times: &[u32]) -> i32 { times .iter() .map(|time| self.signal_strength_at(*time)) .sum() } fn pixel_should_activate(&self, x: usize, y: usize) -> bool { let time = (y * 40 + x + 1) as u32; let sprite_middle = self.value_at(time); ((x as i32) - sprite_middle).abs() <= 1 } }