add day 17

This commit is contained in:
timeshifter
2026-07-02 16:37:36 +02:00
parent d39cc86d4d
commit 78b727ba55
3 changed files with 177 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "day17"
version = "0.1.0"
dependencies = [
"md5",
]
[[package]]
name = "md5"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0"
+7
View File
@@ -0,0 +1,7 @@
[package]
name = "day17"
version = "0.1.0"
edition = "2024"
[dependencies]
md5 = "*"
+154
View File
@@ -0,0 +1,154 @@
use std::{
collections::{HashSet, VecDeque},
fmt::Display,
};
#[cfg(debug_assertions)]
// const PASSCODE: &str = "ihgpwlah";
const PASSCODE: &str = "ulqzkmiv";
#[cfg(not(debug_assertions))]
const PASSCODE: &str = "hhhxzeay";
fn main() {
let state = State::new();
let result = bfs(state);
println!("{result}");
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct State {
route: Route,
position: (usize, usize),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct Route(Vec<Direction>);
impl Display for Route {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for dir in &self.0 {
let the_char = match dir {
Direction::Up => 'U',
Direction::Down => 'D',
Direction::Left => 'L',
Direction::Right => 'R',
};
write!(f, "{the_char}")?;
}
Ok(())
}
}
impl Route {
fn new() -> Self {
Self(vec![])
}
fn push(&mut self, dir: Direction) {
self.0.push(dir);
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum Direction {
Up,
Down,
Left,
Right,
}
impl State {
fn new() -> Self {
Self {
route: Route::new(),
position: (0, 0),
}
}
fn is_goal_state(&self) -> bool {
self.position == (3, 3)
}
fn neighbor_states(&self, passcode: &str) -> impl Iterator<Item = State> {
let input = format!("{}{}", passcode, self.route);
let mut hash = format!("{:x}", md5::compute(input));
hash.truncate(4);
let possible_directions = self.generate_directions_from_hash(&hash);
let mut result = vec![];
for direction in possible_directions {
let mut new_state = self.clone();
new_state.update_position(&direction);
new_state.route.push(direction);
result.push(new_state)
}
result.into_iter()
}
fn generate_directions_from_hash(&self, hash: &str) -> impl Iterator<Item = Direction> {
hash.chars()
.zip([
Direction::Up,
Direction::Down,
Direction::Left,
Direction::Right,
])
.filter(|(c, _)| ('b'..='f').contains(c))
.map(|(_, dir)| dir)
.filter(|dir| match dir {
Direction::Up => self.position.1 > 0,
Direction::Down => self.position.1 < 3,
Direction::Left => self.position.0 > 0,
Direction::Right => self.position.0 < 3,
})
}
fn update_position(&mut self, dir: &Direction) {
match *dir {
Direction::Up => {
self.position.1 -= 1;
}
Direction::Down => {
self.position.1 += 1;
}
Direction::Left => {
self.position.0 -= 1;
}
Direction::Right => {
self.position.0 += 1;
}
}
}
}
fn bfs(start: State) -> Route {
let mut queue = VecDeque::new();
let mut visited = HashSet::new();
visited.insert(start.clone());
queue.push_back(start);
while let Some(current_state) = queue.pop_front() {
if current_state.is_goal_state() {
// return current_state.route;
continue;
}
for neighbor in current_state.neighbor_states(PASSCODE) {
println!("{} {}", neighbor.route.0.len(), neighbor.is_goal_state());
if !visited.contains(&neighbor) {
visited.insert(neighbor.clone());
queue.push_back(neighbor);
}
}
}
panic!("goal state unreachable");
}