add day 17
This commit is contained in:
@@ -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");
|
||||
}
|
||||
Reference in New Issue
Block a user