Advent of Code 2025 adventofcode.com/
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 191 lines 4.1 kB view raw
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}