use crate::solvers::Solver; use std::io::BufRead; pub struct SecretEntrance {} impl SecretEntrance { const START_POSITION: i32 = 50; const DIAL_SIZE: i32 = 100; const ZERO_POSITION: i32 = 0; const POSITIVE_SIGN_CHAR: char = 'R'; const NEGATIVE_SIGN_CHAR: char = 'L'; fn update_position( position: i32, distance: i32, mut zero_hits: u64, mut zero_passes: u64, ) -> (i32, u64, u64) { let mut new_position = position + distance; let rounds = new_position.div_euclid(Self::DIAL_SIZE); zero_passes += u64::try_from(rounds.abs()).unwrap(); new_position -= Self::DIAL_SIZE * rounds; if new_position == Self::ZERO_POSITION { zero_hits += 1; if position != Self::ZERO_POSITION && distance < 0 { zero_passes += 1; } } else if position == Self::ZERO_POSITION && distance < 0 { zero_passes -= 1; } (new_position, zero_hits, zero_passes) } } impl Solver for SecretEntrance { const PUZZLE_INDEX: u8 = 1; const PUZZLE_NAME: &'static str = "Secret Entrance"; fn process_data(&self, reader: R) -> (u64, u64) { let mut position = Self::START_POSITION; let mut zero_hits = 0; let mut zero_passes = 0; let format: String = format!( "{{[{}{}]}}{{d}}", Self::POSITIVE_SIGN_CHAR, Self::NEGATIVE_SIGN_CHAR ); for line in reader.lines().map_while(Result::ok) { let (sign, distance) = scan_fmt!(&line, &format, char, i32).unwrap(); (position, zero_hits, zero_passes) = Self::update_position( position, if sign == Self::POSITIVE_SIGN_CHAR { distance } else { -distance }, zero_hits, zero_passes, ); } (zero_hits, zero_passes) } }