summaryrefslogtreecommitdiff
path: root/2022/src/bin/day_10.rs
blob: 6999c52f9b46aa4ed4c82920c1a258e2fb35f233 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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<dyn std::error::Error>> {
    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<TimeSequence>);

#[derive(Debug, Default)]
struct ProgramResult(Vec<TimeSequence>);

#[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
    }
}