advent_of_code/year2022/
day10.rs1use crate::common::character_recognition::recognize;
2use crate::input::Input;
3
4struct Device {
5 register_x: i32,
6 cycle: i32,
7 accumulated_signal_strength: i32,
8 screen: [bool; Self::NUM_PIXELS],
9}
10
11impl Device {
12 const NUM_PIXELS: usize = 240;
13
14 const fn new() -> Self {
15 Self {
16 register_x: 1,
17 cycle: 1,
18 accumulated_signal_strength: 0,
19 screen: [false; Self::NUM_PIXELS],
20 }
21 }
22
23 fn on_cycle(&mut self, value_to_add: i32) {
24 if ((self.cycle - 1) % 40).abs_diff(self.register_x) <= 1 {
25 self.screen[(self.cycle - 1) as usize] = true;
26 }
27
28 self.cycle = (self.cycle + 1) % (Self::NUM_PIXELS as i32 + 1);
29 self.register_x += value_to_add;
30
31 if (self.cycle - 20) % 40 == 0 {
32 self.accumulated_signal_strength += self.register_x * self.cycle;
33 }
34 }
35}
36
37pub fn solve(input: &Input) -> Result<String, String> {
38 let mut device = Device::new();
39
40 for line in input.text.lines() {
41 device.on_cycle(0);
42
43 if line != "noop" {
44 let value_to_add = i32::from(
45 line.split(' ')
46 .nth(1)
47 .and_then(|num| num.parse::<i16>().ok())
48 .ok_or_else(|| "Invalid input - not \"noop\" or \"addx <i16>\"".to_string())?,
49 );
50 device.on_cycle(value_to_add);
51 };
52 }
53
54 if input.is_part_one() {
55 Ok(device.accumulated_signal_strength.to_string())
56 } else {
57 recognize(&device.screen)
58 }
59}
60
61#[test]
62pub fn tests() {
63 use crate::input::{test_part_one, test_part_two};
64
65 let test_input = "addx 15
66addx -11
67addx 6
68addx -3
69addx 5
70addx -1
71addx -8
72addx 13
73addx 4
74noop
75addx -1
76addx 5
77addx -1
78addx 5
79addx -1
80addx 5
81addx -1
82addx 5
83addx -1
84addx -35
85addx 1
86addx 24
87addx -19
88addx 1
89addx 16
90addx -11
91noop
92noop
93addx 21
94addx -15
95noop
96noop
97addx -3
98addx 9
99addx 1
100addx -3
101addx 8
102addx 1
103addx 5
104noop
105noop
106noop
107noop
108noop
109addx -36
110noop
111addx 1
112addx 7
113noop
114noop
115noop
116addx 2
117addx 6
118noop
119noop
120noop
121noop
122noop
123addx 1
124noop
125noop
126addx 7
127addx 1
128noop
129addx -13
130addx 13
131addx 7
132noop
133addx 1
134addx -33
135noop
136noop
137noop
138addx 2
139noop
140noop
141noop
142addx 8
143noop
144addx -1
145addx 2
146addx 1
147noop
148addx 17
149addx -9
150addx 1
151addx 1
152addx -3
153addx 11
154noop
155noop
156addx 1
157noop
158addx 1
159noop
160noop
161addx -13
162addx -19
163addx 1
164addx 3
165addx 26
166addx -30
167addx 12
168addx -1
169addx 3
170addx 1
171noop
172noop
173noop
174addx -9
175addx 18
176addx 1
177addx 2
178noop
179noop
180addx 9
181noop
182noop
183noop
184addx -1
185addx 2
186addx -37
187addx 1
188addx 3
189noop
190addx 15
191addx -21
192addx 22
193addx -6
194addx 1
195noop
196addx 2
197addx 1
198noop
199addx -10
200noop
201noop
202addx 20
203addx 1
204addx 2
205addx 2
206addx -6
207addx -11
208noop
209noop
210noop";
211 test_part_one!(test_input => "13140".to_string());
212
213 let real_input = include_str!("day10_input.txt");
214 test_part_one!(real_input => "12740".to_string());
215 test_part_two!(real_input => "RBPARAGF".to_string());
216}
217
218#[cfg(feature = "count-allocations")]
219#[test]
220pub fn single_to_string_memory_allocation() {
221 let real_input = include_str!("day10_input.txt");
222 let allocations = allocation_counter::measure(|| {
223 assert!(solve(&Input::part_one(real_input)).is_ok());
224 });
225 assert_eq!(allocations.count_total, 1);
226 let allocations = allocation_counter::measure(|| {
227 assert!(solve(&Input::part_two(real_input)).is_ok());
228 });
229 assert_eq!(allocations.count_total, 1);
230}