2025: day01
This commit is contained in:
parent
d9c8d8155c
commit
d310ec45c0
8 changed files with 4574 additions and 1 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
|
@ -133,6 +133,14 @@ dependencies = [
|
|||
"criterion 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aoc2025"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"aoc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[workspace]
|
||||
members = ["aoc20*", "aoc20*/aoc20*_bench"]
|
||||
|
||||
default-members = ["aoc2023"]
|
||||
default-members = ["aoc2025"]
|
||||
|
||||
resolver = "2"
|
||||
|
||||
|
|
|
|||
16
aoc2025/Cargo.toml
Normal file
16
aoc2025/Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "aoc2025"
|
||||
version = "0.1.0"
|
||||
authors = ["Antoine Martin <antoine@alarsyo.net>"]
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
aoc = { path = "../aoc" }
|
||||
anyhow = "1.0"
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "aoc2025"
|
||||
path = "src/main.rs"
|
||||
4392
aoc2025/input/day01.txt
Normal file
4392
aoc2025/input/day01.txt
Normal file
File diff suppressed because it is too large
Load diff
10
aoc2025/input/day01_provided.txt
Normal file
10
aoc2025/input/day01_provided.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
L68
|
||||
L30
|
||||
R48
|
||||
L5
|
||||
R60
|
||||
L55
|
||||
L1
|
||||
L99
|
||||
R14
|
||||
L82
|
||||
135
aoc2025/src/day01.rs
Normal file
135
aoc2025/src/day01.rs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
use std::{fmt::Write, str::FromStr};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
1
aoc2025/src/lib.rs
Normal file
1
aoc2025/src/lib.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub mod day01;
|
||||
11
aoc2025/src/main.rs
Normal file
11
aoc2025/src/main.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use aoc::DayFunc;
|
||||
|
||||
use aoc2025::day01;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let days: &[DayFunc] = &[day01::run];
|
||||
|
||||
aoc::run(days)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue