95 lines
2.3 KiB
Rust
95 lines
2.3 KiB
Rust
|
|
#![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)
|
||
|
|
}
|
||
|
|
}
|