day 1
This commit is contained in:
commit
078fb7b1b0
4 changed files with 4965 additions and 0 deletions
7
aoc-2025-1/Cargo.lock
generated
Normal file
7
aoc-2025-1/Cargo.lock
generated
Normal 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
6
aoc-2025-1/Cargo.toml
Normal 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
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
172
aoc-2025-1/src/main.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue