This commit is contained in:
Stuart Axelbrooke 2025-12-09 21:59:27 -08:00
commit 078fb7b1b0
4 changed files with 4965 additions and 0 deletions

7
aoc-2025-1/Cargo.lock generated Normal file
View file

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aoc-2025-1"
version = "0.1.0"

6
aoc-2025-1/Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "aoc-2025-1"
version = "0.1.0"
edition = "2024"
[dependencies]

4780
aoc-2025-1/input.txt Normal file

File diff suppressed because it is too large Load diff

172
aoc-2025-1/src/main.rs Normal file
View file

@ -0,0 +1,172 @@
use std::fs;
fn main() {
let input_contents = fs::read_to_string("input.txt").expect("read file");
println!("Password: {:?}", calculate_password(&input_contents));
}
fn calculate_password(input: &str) -> PasswordSafe {
input
.split("\n")
.into_iter()
.filter(|s| s.len() > 0)
.fold(PasswordSafe::default(), |psafe, raw_spin| {
psafe.spin_dial(raw_spin.into())
})
}
#[derive(Debug)]
struct PasswordSafe {
position: i32,
zero_landings: u64,
zero_crossings: u64,
}
struct Spin {
ticks: i32,
}
impl Default for PasswordSafe {
fn default() -> Self {
Self {
position: 50,
zero_landings: 0,
zero_crossings: 0,
}
}
}
impl PasswordSafe {
fn spin_dial(self, spin: Spin) -> Self {
// Zero Crossings
let zero_crossing_delta: u64 = match spin.ticks {
t if t > 0 => {
let res = (self.position + t) as u64 / 100;
// println!("{} -> {} => {}", self.position, t, res);
res
},
t if t < 0 => {
let res = (self.position - 100 + t).abs() as u64 / 100;
// println!("hm {}, {}, {}", self.position, t, (self.position - 100 + t).abs());
// println!("{} <- {} => {}", self.position, t, res);
res - (match self.position {
0 => 1,
_ => 0
})
},
_ => panic!("0 is an invalid spin"),
};
let zero_crossings: u64 = self.zero_crossings + zero_crossing_delta;
// Zero Landings
let new_position = (self.position + spin.ticks) % 100;
let position = match new_position {
p if p < 0 => p + 100,
p => p,
};
let zero_landings = match position {
0 => self.zero_landings + 1,
_ => self.zero_landings,
};
// println!("Spun to `{}`", position);
Self {
position,
zero_landings,
zero_crossings,
}
}
}
impl From<&str> for Spin {
fn from(s: &str) -> Spin {
let (direction, raw_num) = s.split_at(1);
let num: i32 = raw_num
.parse()
.expect(&format!("Couldn't parse num `{}`", raw_num));
let ticks = match direction {
"L" => -num,
"R" => num,
_ => panic!("invalid input spin: `{}`", s),
};
Spin { ticks }
}
}
#[cfg(test)]
mod tests {
use crate::calculate_password;
use std::fs;
const TEST_INPUT: &str = "L68
L30
R48
L5
R60
L55
L1
L99
R14
L82
";
#[test]
fn test_zero_landings() {
let calculated = calculate_password(TEST_INPUT);
assert_eq!(calculated.zero_landings, 3);
}
#[test]
fn zero_crossings_guess_1() {
let input_contents = fs::read_to_string("input.txt").expect("read file");
let calculated = calculate_password(&input_contents);
assert!(calculated.zero_crossings > 5598);
assert!(calculated.zero_crossings < 7509);
assert_eq!(calculated.zero_crossings, 6907);
}
#[test]
fn negative_unit_zero_crossing() {
let calculated = calculate_password("L50
");
println!("{:?}", calculated);
assert_eq!(calculated.zero_crossings, 1);
}
#[test]
fn negative_unit_zero_crossing_5() {
let calculated = calculate_password("L550
L1
L1
L1
L1
");
println!("{:?}", calculated);
assert_eq!(calculated.zero_crossings, 6);
}
#[test]
fn positive_unit_zero_crossing_5() {
let calculated = calculate_password("R550
R1
R1
R1
R1
");
println!("{:?}", calculated);
assert_eq!(calculated.zero_crossings, 6);
}
#[test]
fn zig_zag() {
let calculated = calculate_password("L51
R2
L2
R2
L2
R2
L2
");
println!("{:?}", calculated);
assert_eq!(calculated.zero_crossings, 7);
}
}