fork
Configure Feed
Select the types of activity you want to include in your feed.
Advent of Code 2025
adventofcode.com/
fork
Configure Feed
Select the types of activity you want to include in your feed.
1use std::io::{Read, Write};
2use std::{fmt::Display, io};
3
4use anyhow::{Error, Result};
5use log::debug;
6
7enum Direction {
8 RIGHT,
9 LEFT,
10}
11
12impl Display for Direction {
13 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 f.write_str(match self {
15 Direction::LEFT => "Left",
16 Direction::RIGHT => "Right",
17 })?;
18 Ok(())
19 }
20}
21
22struct Instruction {
23 direction: Direction,
24 distance: i32,
25}
26
27impl Display for Instruction {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 f.write_fmt(format_args!("{} {}", self.direction, self.distance))?;
30 Ok(())
31 }
32}
33
34fn parse_line(line: &str) -> Result<Instruction> {
35 let mut chars = line.chars();
36 let direction = match chars.next() {
37 Some('R') => Direction::RIGHT,
38 Some('L') => Direction::LEFT,
39 default => return Err(Error::msg(format!("Invalid direction: {:?}", default))),
40 };
41
42 let distance: i32 = line[1..].parse()?;
43
44 Ok(Instruction {
45 direction,
46 distance,
47 })
48}
49
50fn day_01_part1(input: &str) -> String {
51 let mut dial: i32 = 50;
52 let mut count: u32 = 0;
53 for line in input.lines() {
54 if line.len() == 0 {
55 continue;
56 };
57 let instruction = match parse_line(line) {
58 Ok(i) => i,
59 Err(e) => panic!("{:?}", e),
60 };
61 match instruction.direction {
62 Direction::LEFT => dial -= instruction.distance,
63 Direction::RIGHT => dial += instruction.distance,
64 }
65
66 dial = dial.rem_euclid(100).abs();
67
68 debug!("Moved {} to get to {}", instruction, dial);
69
70 if dial == 0 {
71 count += 1;
72 }
73 }
74
75 format!("{}\n", count)
76}
77
78fn day_01_part2(input: &str) -> String {
79 let mut dial: i32 = 50;
80 let mut count: i32 = 0;
81 for line in input.lines() {
82 if line.len() == 0 {
83 continue;
84 };
85 let instruction = match parse_line(line) {
86 Ok(i) => i,
87 Err(e) => panic!("{:?}", e),
88 };
89 let mut clicks = instruction.distance / 100;
90 let offset = instruction.distance % 100;
91 let original_dial = dial;
92
93 match instruction.direction {
94 Direction::LEFT => dial -= offset,
95 Direction::RIGHT => dial += offset,
96 }
97
98 // We already took care of multiples of 100, so this should be valid:
99 if dial > 99 || dial == 0 || (dial < 0 && original_dial != 0) {
100 clicks += 1;
101 }
102 dial = dial.rem_euclid(100).abs();
103
104 debug!(
105 "Moved {} to get to {}, clicking {} times",
106 instruction, dial, clicks
107 );
108
109 count += clicks;
110 }
111
112 format!("{}\n", count)
113}
114
115fn main() {
116 env_logger::init();
117 let mut input = String::new();
118 let mut stdin = io::stdin();
119 let mut stdout = io::stdout();
120 stdin.read_to_string(&mut input).unwrap();
121 println!("Part 1:");
122 let output_1 = day_01_part1(&input);
123 stdout.write(output_1.as_bytes()).unwrap();
124 println!("Part 2:");
125 let output_2 = day_01_part2(&input);
126 stdout.write(output_2.as_bytes()).unwrap();
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 use std::sync::Once;
134 static INIT: Once = Once::new();
135 fn setup() {
136 INIT.call_once(|| {
137 env_logger::init();
138 });
139 }
140
141 #[test]
142 fn sample_part1() {
143 setup();
144 let input = r#"
145L68
146L30
147R48
148L5
149R60
150L55
151L1
152L99
153R14
154L82
155"#;
156 let expected = "3\n";
157
158 let result = day_01_part1(&input);
159 assert_eq!(result.as_str(), expected);
160 }
161
162 #[test]
163 fn sample_part2() {
164 setup();
165 let input = r#"
166L68
167L30
168R48
169L5
170R60
171L55
172L1
173L99
174R14
175L82
176"#;
177 let expected = "6\n";
178
179 let result = day_01_part2(&input);
180 assert_eq!(result.as_str(), expected);
181 }
182 #[test]
183 fn sample_part2_rot() {
184 setup();
185 let input = "R1000\nR50\nL1\nR2\n";
186 let expected = "12\n";
187
188 let result = day_01_part2(&input);
189 assert_eq!(result.as_str(), expected);
190 }
191}