Files
Advent-of-Code-2026-Rust/src/day1/dial_position.rs
2025-12-01 23:02:16 +01:00

178 lines
5.1 KiB
Rust

pub struct DialPosition {
pub current_position: i16,
pub zero_hits_count: u32,
}
impl DialPosition {
const DIAL_MAX: i16 = 99;
const DIAL_COUNT: i16 = 100;
pub fn new(current_position: i16) -> Self {
Self {
current_position,
zero_hits_count: 0,
}
}
pub fn rotated_left(&self, rotation: u64) -> Self {
let (remaining, reduce_hits_count) = DialPosition::reduce_rotation(rotation);
let current_position_u64 = self.current_position;
let (result, clamp_hits_count) = self.clamp(current_position_u64 - remaining);
Self {
current_position: result,
zero_hits_count: self.zero_hits_count + clamp_hits_count + reduce_hits_count,
}
}
pub fn rotated_right(&self, rotation: u64) -> Self {
let (remaining, reduce_hits_count) = DialPosition::reduce_rotation(rotation);
let (result, clamp_hits_count) = self.clamp(self.current_position + remaining);
Self {
current_position: result,
zero_hits_count: self.zero_hits_count + clamp_hits_count + reduce_hits_count,
}
}
fn reduce_rotation(rotation: u64) -> (i16, u32) {
let mut remaining = rotation;
let mut zero_hits_count = 0;
while remaining > u64::try_from(DialPosition::DIAL_MAX).unwrap() {
remaining -= u64::try_from(DialPosition::DIAL_COUNT).unwrap();
zero_hits_count += 1;
}
(i16::try_from(remaining).unwrap(), zero_hits_count)
}
fn clamp(&self, value: i16) -> (i16, u32) {
if value > DialPosition::DIAL_MAX {
(value - 100, 1)
} else if value < 0 {
(100 + value, if self.current_position != 0 { 1 } else { 0 })
} else {
(value, if value == 0 { 1 } else { 0 })
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dial_rotated_right_from_0_by_2_gives_2() {
let result = DialPosition::new(0).rotated_right(2);
assert_eq!(result.current_position, 2);
}
#[test]
fn dial_rotated_right_from_0_by_102_gives_2() {
let result = DialPosition::new(0).rotated_right(102);
assert_eq!(result.current_position, 2);
}
#[test]
fn dial_rotated_left_from_0_by_2_gives_98() {
let result = DialPosition::new(0).rotated_left(2);
assert_eq!(result.current_position, 98);
}
#[test]
fn dial_rotated_left_from_0_by_102_gives_98() {
let result = DialPosition::new(0).rotated_left(102);
assert_eq!(result.current_position, 98);
}
#[test]
fn dial_rotated_left_from_5_by_105_gives_0() {
let result = DialPosition::new(5).rotated_left(105);
assert_eq!(result.current_position, 0);
}
#[test]
fn dial_rotated_right_from_5_by_105_gives_10() {
let result = DialPosition::new(5).rotated_right(105);
assert_eq!(result.current_position, 10);
}
}
// part 2
#[test]
fn dial_from_50_right_1000_hits_zero_10_times() {
let result = DialPosition::new(50).rotated_right(1000);
assert_eq!(result.current_position, 50);
assert_eq!(result.zero_hits_count, 10);
}
#[test]
fn dial_from_50_left_68_hits_zero_once() {
let result = DialPosition::new(50).rotated_left(68);
assert_eq!(result.current_position, 82);
assert_eq!(result.zero_hits_count, 1);
}
#[test]
fn dial_from_82_left_30_no_zero_hit() {
let result = DialPosition::new(82).rotated_left(30);
assert_eq!(result.current_position, 52);
assert_eq!(result.zero_hits_count, 0);
}
#[test]
fn dial_from_52_right_48_lands_on_zero() {
let result = DialPosition::new(52).rotated_right(48);
assert_eq!(result.current_position, 0);
assert_eq!(result.zero_hits_count, 1);
}
#[test]
fn dial_from_0_left_5_no_zero_hit() {
let result = DialPosition::new(0).rotated_left(5);
assert_eq!(result.current_position, 95);
assert_eq!(result.zero_hits_count, 0);
}
#[test]
fn dial_from_95_right_60_hits_zero_once() {
let result = DialPosition::new(95).rotated_right(60);
assert_eq!(result.current_position, 55);
assert_eq!(result.zero_hits_count, 1);
}
#[test]
fn dial_from_55_left_55_lands_on_zero() {
let result = DialPosition::new(55).rotated_left(55);
assert_eq!(result.current_position, 0);
assert_eq!(result.zero_hits_count, 1);
}
#[test]
fn dial_from_0_left_1_no_zero_hit() {
let result = DialPosition::new(0).rotated_left(1);
assert_eq!(result.current_position, 99);
assert_eq!(result.zero_hits_count, 0);
}
#[test]
fn dial_from_99_left_99_lands_on_zero() {
let result = DialPosition::new(99).rotated_left(99);
assert_eq!(result.current_position, 0);
assert_eq!(result.zero_hits_count, 1);
}
#[test]
fn dial_from_0_right_14_no_zero_hit() {
let result = DialPosition::new(0).rotated_right(14);
assert_eq!(result.current_position, 14);
assert_eq!(result.zero_hits_count, 0);
}
#[test]
fn dial_from_14_left_82_hits_zero_once() {
let result = DialPosition::new(14).rotated_left(82);
assert_eq!(result.current_position, 32);
assert_eq!(result.zero_hits_count, 1);
}