advent-of-code/aoc2025/src/day01.rs
Antoine Martin 7433687d69 2025: fix cargo fmt
Turns out rustfmt needs a --edition 2024 flag (which cargo fmt adds
automatically), otherwise some imports change order. Of course my editor
is configured to use rustfmt via apheleia, which does not support cargo
fmt. Urgh.
2025-12-08 16:39:16 +01:00

135 lines
3.3 KiB
Rust

use std::{fmt::Write, str::FromStr};
use anyhow::{Result, bail};
const INPUT: &str = include_str!("../input/day01.txt");
const DIAL_SIZE: u16 = 100;
pub fn run() -> Result<String> {
let mut res = String::with_capacity(128);
writeln!(res, "part 1: {}", part1(INPUT)?)?;
writeln!(res, "part 2: {}", part2(INPUT)?)?;
Ok(res)
}
enum Rotation {
Left(u16),
Right(u16),
}
impl FromStr for Rotation {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
let dir = &s[..1];
let num = s[1..].parse()?;
match dir {
"L" => Ok(Rotation::Left(num)),
"R" => Ok(Rotation::Right(num)),
_ => bail!("rotation can only be left or right, got `{}'", dir),
}
}
}
impl Rotation {
fn apply(&self, state: u16) -> u16 {
match self {
Rotation::Left(num) => {
let num = num % DIAL_SIZE;
if num > state {
DIAL_SIZE - (num - state)
} else {
state - num
}
}
Rotation::Right(num) => (state + num) % DIAL_SIZE,
}
}
/// Counts the number of zeroes encountered while rotating the dial. Does NOT take the initial
/// state into account if it is 0.
fn apply_and_count_zeroes(&self, state: u16) -> (u16, usize) {
match self {
Rotation::Left(num) => {
let zeroes = (num / DIAL_SIZE) as usize;
let num = num % DIAL_SIZE;
if num > state {
(
DIAL_SIZE - (num - state),
zeroes + if state != 0 { 1 } else { 0 },
)
} else {
let new_state = state - num;
(new_state, zeroes + if new_state == 0 { 1 } else { 0 })
}
}
Rotation::Right(num) => (
(state + num) % DIAL_SIZE,
((state + num) / DIAL_SIZE) as usize,
),
}
}
}
fn part1(input: &str) -> Result<usize> {
let rotations = input
.lines()
.map(Rotation::from_str)
.collect::<Result<Vec<Rotation>>>()?;
let res = rotations
.iter()
.fold((50, 0), |(state, mut count), rot| {
let new_state = rot.apply(state);
if new_state == 0 {
count += 1;
}
(new_state, count)
})
.1;
Ok(res)
}
fn part2(input: &str) -> Result<usize> {
let rotations = input
.lines()
.map(Rotation::from_str)
.collect::<Result<Vec<Rotation>>>()?;
let res = rotations
.iter()
.fold((50, 0), |(state, count), rot| {
let (new_state, zeroes) = rot.apply_and_count_zeroes(state);
(new_state, count + zeroes)
})
.1;
Ok(res)
}
#[cfg(test)]
mod tests {
use super::*;
const PROVIDED: &str = include_str!("../input/day01_provided.txt");
#[test]
fn part1_provided() {
assert_eq!(part1(PROVIDED).unwrap(), 3);
}
#[test]
fn part1_real() {
assert_eq!(part1(INPUT).unwrap(), 1092);
}
#[test]
fn part2_provided() {
assert_eq!(part2(PROVIDED).unwrap(), 6);
}
#[test]
fn part2_real() {
assert_eq!(part2(INPUT).unwrap(), 6616);
}
}