diff --git a/src/days.rs b/src/days.rs index 9d545ea..610149f 100644 --- a/src/days.rs +++ b/src/days.rs @@ -14,7 +14,7 @@ pub mod d13; pub mod d14; pub mod d15; pub mod d16; -// pub mod d17; +pub mod d17; // pub mod d18; // pub mod d19; // pub mod d20; diff --git a/src/days/d17.rs b/src/days/d17.rs new file mode 100644 index 0000000..b5a54cc --- /dev/null +++ b/src/days/d17.rs @@ -0,0 +1,94 @@ +#![allow(non_upper_case_globals)] +#![allow(unused_imports)] + +use md5::Digest; + +use crate::prelude::*; + +pub type I = &'static str; +pub type O = String; +pub type O2 = usize; + +const _cand: [(isize, isize, char); 4] = [(-1, 0, 'U'), (1, 0, 'D'), (0, -1, 'L'), (0, 1, 'R')]; + +fn _open_doors ((y, x): (usize, usize), digest: Digest) -> Vec<(usize, usize, char)> { + let repr = format!("{:x}", digest); + let access: [char; 4] = repr.chars().take(4).collect_vec().try_into().unwrap(); + + _cand.iter() + .enumerate() + .filter_map(|(i, &(dy, dx, n))| match (y.checked_add_signed(dy), x.checked_add_signed(dx)) { + (Some(y), Some(x)) => if y <= 3 && x <= 3 { Some((y, x, n, i)) } else { None }, + _ => None + }) + .filter(|(_, _, _, idx)| ('b'..='f').contains(&access[*idx])) + .map(|(a, b, c, _)| (a, b, c)) + .collect() +} + +fn _digest (pass: &'static str, i: &str) -> Digest { + let full = format!("{pass}{i}"); + md5::compute(full) +} + +fn _dfs (cur: (usize, usize), path: &mut String, pass: &'static str) -> bool { + if cur == (3, 3) { return true; } else { + let digest = _digest(pass, &path); + let doors = _open_doors(cur, digest); + for (ny, nx, p) in doors { + path.push(p); + if _dfs((ny, nx), path, pass) { + return true; + } else { + path.pop(); + } + } + return false; + } +} + +fn _dfs_max (cur: (usize, usize), path: &mut String, pass: &'static str, max: &mut usize) { + if cur == (3, 3) { + *max = (*max).max(path.len()); + } else { + let digest = _digest(pass, &path); + let doors = _open_doors(cur, digest); + for (ny, nx, p) in doors { + path.push(p); + _dfs_max((ny, nx), path, pass, max); + path.pop(); + } + } +} + +fn _silver (data: I) -> O { + let mut path = String::new(); + _dfs((0, 0), &mut path, data); + path +} + +fn _gold (data: I) -> O2 { + let mut path = String::new(); + let mut max = 0; + _dfs_max((0, 0), &mut path, data, &mut max); + max +} + +#[cfg(test)] +mod test { + use super::*; + + const pass: &'static str = "edjrjqaa"; + + #[test] + fn silver () { + let ans = _silver(pass); + assert_eq!(ans, s!("DUDRDLRRRD")) + } + + #[test] + fn gold () { + let ans = _gold(pass); + assert_eq!(ans, 502) + } +}