more D18 wip
This commit is contained in:
parent
f4017dd12a
commit
970ad53ce5
@ -9,3 +9,4 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
grid = { path = "../grid" }
|
grid = { path = "../grid" }
|
||||||
lazy_static = "1.3.0"
|
lazy_static = "1.3.0"
|
||||||
|
rayon = "1.2.1"
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use grid::*;
|
use grid::*;
|
||||||
|
use rayon::prelude::*;
|
||||||
use std::char;
|
use std::char;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::io::{self, BufRead};
|
use std::io::{self, BufRead};
|
||||||
use std::sync::Mutex;
|
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
|
use std::sync::Mutex;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
@ -14,27 +15,24 @@ struct Door(char);
|
|||||||
struct Key(char);
|
struct Key(char);
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref MAP: Mutex<HashMap<Position2D, char>> = Mutex::new(
|
static ref BEST: Mutex<usize> = Mutex::new(999999);
|
||||||
io::stdin()
|
|
||||||
.lock()
|
|
||||||
.lines()
|
|
||||||
.enumerate()
|
|
||||||
.flat_map(move |(y, l)| l
|
|
||||||
.unwrap()
|
|
||||||
.to_owned()
|
|
||||||
.chars()
|
|
||||||
.enumerate()
|
|
||||||
.map(move |(x, c)| ((x, y).into(), c))
|
|
||||||
.collect::<Vec<_>>())
|
|
||||||
.collect()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(p: &Position2D) -> Option<char> {
|
fn too_slow(i: usize) -> bool {
|
||||||
MAP.lock().unwrap().get(p).copied()
|
let best = BEST.lock().unwrap();
|
||||||
|
*best < i
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace(i: usize) {
|
||||||
|
let mut best = BEST.lock().unwrap();
|
||||||
|
if i < *best {
|
||||||
|
println!("Best so far: {}", i);
|
||||||
|
*best = i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_neighbors(
|
fn visit_neighbors(
|
||||||
|
map: &HashMap<Position2D, char>,
|
||||||
position: Position2D,
|
position: Position2D,
|
||||||
steps: usize,
|
steps: usize,
|
||||||
distances: &mut HashMap<Position2D, usize>,
|
distances: &mut HashMap<Position2D, usize>,
|
||||||
@ -43,21 +41,21 @@ fn visit_neighbors(
|
|||||||
mut doors: HashSet<Door>,
|
mut doors: HashSet<Door>,
|
||||||
mut keys: HashSet<Key>,
|
mut keys: HashSet<Key>,
|
||||||
) {
|
) {
|
||||||
let c = get(&position).unwrap();
|
let c = map.get(&position).unwrap();
|
||||||
if c.is_alphabetic() {
|
if c.is_alphabetic() {
|
||||||
if c.is_lowercase() {
|
if c.is_lowercase() {
|
||||||
dependencies.insert(Key { 0: c }, (keys.clone(), doors.clone()));
|
dependencies.insert(Key { 0: *c }, (keys.clone(), doors.clone()));
|
||||||
keys.insert(Key { 0: c });
|
keys.insert(Key { 0: *c });
|
||||||
}
|
}
|
||||||
if c.is_uppercase() {
|
if c.is_uppercase() {
|
||||||
door_dependencies.insert(Door { 0: c }, doors.clone());
|
door_dependencies.insert(Door { 0: *c }, doors.clone());
|
||||||
doors.insert(Door { 0: c });
|
doors.insert(Door { 0: *c });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut unvisited = Vec::new();
|
let mut unvisited = Vec::new();
|
||||||
// TODO: fix ownership and make this a single filter().inspect().for_each()
|
// TODO: fix ownership and make this a single filter().inspect().for_each()
|
||||||
for (_, p) in &position.neighbors() {
|
for (_, p) in &position.neighbors() {
|
||||||
match get(p) {
|
match map.get(p) {
|
||||||
Some('#') => (),
|
Some('#') => (),
|
||||||
_ => {
|
_ => {
|
||||||
if distances.get(p).is_none() {
|
if distances.get(p).is_none() {
|
||||||
@ -65,7 +63,7 @@ fn visit_neighbors(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if get(p) != Some('#') && distances.get(p).is_none() {
|
if map.get(p) != Some(&'#') && distances.get(p).is_none() {
|
||||||
unvisited.push(p.to_owned());
|
unvisited.push(p.to_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,6 +77,7 @@ fn visit_neighbors(
|
|||||||
}
|
}
|
||||||
for p in &unvisited {
|
for p in &unvisited {
|
||||||
visit_neighbors(
|
visit_neighbors(
|
||||||
|
map,
|
||||||
p.to_owned(),
|
p.to_owned(),
|
||||||
steps + 1,
|
steps + 1,
|
||||||
distances,
|
distances,
|
||||||
@ -91,6 +90,7 @@ fn visit_neighbors(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn traverse(
|
fn traverse(
|
||||||
|
map: &HashMap<Position2D, char>,
|
||||||
start: Position2D,
|
start: Position2D,
|
||||||
) -> (
|
) -> (
|
||||||
HashMap<Position2D, usize>,
|
HashMap<Position2D, usize>,
|
||||||
@ -102,6 +102,7 @@ fn traverse(
|
|||||||
let mut door_dependencies = HashMap::new();
|
let mut door_dependencies = HashMap::new();
|
||||||
distances.insert(start, 0usize);
|
distances.insert(start, 0usize);
|
||||||
visit_neighbors(
|
visit_neighbors(
|
||||||
|
map,
|
||||||
start,
|
start,
|
||||||
0,
|
0,
|
||||||
&mut distances,
|
&mut distances,
|
||||||
@ -123,52 +124,59 @@ fn find_keys_at_dead_ends(deps: &HashMap<Key, (HashSet<Key>, HashSet<Door>)>) ->
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find(c: char) -> Option<Position2D> {
|
fn find(map: &HashMap<Position2D, char>, c: char) -> Option<Position2D> {
|
||||||
let map = MAP.lock().unwrap();
|
|
||||||
map.keys().find(|p| map.get(&p) == Some(&c)).copied()
|
map.keys().find(|p| map.get(&p) == Some(&c)).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_field(p: &Position2D) {
|
fn clear_field(map: &mut HashMap<Position2D, char>, p: &Position2D) {
|
||||||
MAP.lock().unwrap().insert(*p, '.');
|
map.insert(*p, '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(k: Key) {
|
fn remove(map: &mut HashMap<Position2D, char>, k: Key) {
|
||||||
let key_pos = find(k.0).unwrap();
|
let key_pos = find(map, k.0).unwrap();
|
||||||
clear_field(&key_pos);
|
clear_field(map, &key_pos);
|
||||||
if let Some(door_pos) = find(k.0.to_uppercase().next().unwrap()) {
|
if let Some(door_pos) = find(map, k.0.to_uppercase().next().unwrap()) {
|
||||||
clear_field(&door_pos);
|
clear_field(map, &door_pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn distance_to_door(k: &Key) -> usize {
|
fn distance_to_door(map: &HashMap<Position2D, char>, k: &Key) -> usize {
|
||||||
let (distances, _, _) = traverse(find(k.0).unwrap());
|
let (distances, _, _) = traverse(map, find(map, k.0).unwrap());
|
||||||
let door_pos = find(k.0.to_uppercase().next().unwrap());
|
let door_pos = find(map, k.0.to_uppercase().next().unwrap());
|
||||||
*door_pos.map(|p| distances.get(&p).unwrap()).unwrap_or(&10)
|
*door_pos.map(|p| distances.get(&p).unwrap()).unwrap_or(&10)
|
||||||
}
|
}
|
||||||
fn distance_to_locked_door(k: &Key) -> usize {
|
fn distance_to_locked_door(map: &HashMap<Position2D, char>, k: &Key) -> usize {
|
||||||
let (distances, _, doors) = traverse(find(k.0).unwrap());
|
let (distances, _, doors) = traverse(map, find(map, k.0).unwrap());
|
||||||
*doors.keys()
|
*doors
|
||||||
.map(|d| find(d.0).unwrap())
|
.keys()
|
||||||
|
.map(|d| find(map, d.0).unwrap())
|
||||||
.map(|p| distances.get(&p).unwrap_or(&9999999999999))
|
.map(|p| distances.get(&p).unwrap_or(&9999999999999))
|
||||||
.min()
|
.min()
|
||||||
.unwrap_or(&0)
|
.unwrap_or(&0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn next_key(
|
||||||
let mut pos = find('@').unwrap();
|
map: &mut HashMap<Position2D, char>,
|
||||||
let mut steps = 0;
|
pos: &Position2D,
|
||||||
let (_, dependencies, _) = traverse(pos.to_owned());
|
steps: usize,
|
||||||
let mut i = 0;
|
) -> usize {
|
||||||
while i < dependencies.len() {
|
if too_slow(steps) {
|
||||||
println!("{}", i);
|
// println!("Aborting after {} steps", steps);
|
||||||
let (distances, dependencies, door_dependencies) = traverse(pos.to_owned());
|
return 999999;
|
||||||
|
}
|
||||||
|
let (distances, dependencies, door_dependencies) = traverse(map, pos.to_owned());
|
||||||
//dbg!(distances.get(&find('c').unwrap()));
|
//dbg!(distances.get(&find('c').unwrap()));
|
||||||
|
if dependencies.len() == 0 {
|
||||||
|
// println!("End of path after {} steps", steps);
|
||||||
|
replace(steps);
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
let reachable_doors: HashSet<_> = door_dependencies
|
let reachable_doors: HashSet<_> = door_dependencies
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(door, doors)| if doors.is_empty() { Some(door) } else { None })
|
.filter_map(|(door, doors)| if doors.is_empty() { Some(door) } else { None })
|
||||||
.collect();
|
.collect();
|
||||||
let useful_keys = dependencies
|
let mut useful_keys: Vec<_> = dependencies
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, (_, d))| d.is_empty())
|
.filter(|(_, (_, d))| d.is_empty())
|
||||||
.filter(|(k, _)| {
|
.filter(|(k, _)| {
|
||||||
@ -178,32 +186,78 @@ fn main() {
|
|||||||
})
|
})
|
||||||
//.min_by_key(|(k, _)| distances.get(&find(k.0).unwrap()))
|
//.min_by_key(|(k, _)| distances.get(&find(k.0).unwrap()))
|
||||||
//.unwrap()
|
//.unwrap()
|
||||||
.map(|(k, _)| (k, distances.get(&find(k.0).unwrap()).unwrap().mul(2)));
|
.map(|(k, _)| {
|
||||||
|
(
|
||||||
|
k,
|
||||||
|
distances
|
||||||
|
.get(&find(map, k.0).expect("could not find key"))
|
||||||
|
.expect("No distance to key")
|
||||||
|
.mul(1),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
//.min_by_key(|k| )
|
//.min_by_key(|k| )
|
||||||
|
|
||||||
let next: Key = find_keys_at_dead_ends(&dependencies)
|
let dead_end_keys = find_keys_at_dead_ends(&dependencies);
|
||||||
|
let mut next: Vec<_> = dead_end_keys
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|k| dependencies.get(k).unwrap().1.is_empty())
|
.filter(|k| dependencies.get(k).expect("not in deps").1.is_empty())
|
||||||
.map(|k| (k, distances.get(&find(k.0).unwrap()).unwrap().mul(1)))
|
.map(|k| {
|
||||||
|
(
|
||||||
|
k,
|
||||||
|
distances
|
||||||
|
.get(&find(map, k.0).expect("could not find key #2"))
|
||||||
|
.expect("No distance to key #2")
|
||||||
|
.mul(1),
|
||||||
|
)
|
||||||
|
})
|
||||||
//.min_by_key(|k| distances.get(&find(k.0).unwrap()))
|
//.min_by_key(|k| distances.get(&find(k.0).unwrap()))
|
||||||
.chain(useful_keys)
|
//.chain(useful_keys)
|
||||||
.min_by_key(|(k, n)| *n)// + distance_to_locked_door(&k))// * 100 + k.0 as usize)
|
.collect();
|
||||||
.expect("no candidate found")
|
next.sort_by_key(|(k, n)| *n);//*3 + distance_to_door(map, k));
|
||||||
.0
|
useful_keys.sort_by_key(|(k, n)| *n);
|
||||||
.to_owned();
|
useful_keys.reverse();
|
||||||
dbg!(&next);
|
useful_keys.pop().map(|k| next.insert(0, k));
|
||||||
let next_pos = find(next.0).unwrap();
|
useful_keys.pop().map(|k| next.push(k));
|
||||||
steps += distances.get(&next_pos).unwrap();
|
useful_keys.pop().map(|k| next.push(k));
|
||||||
pos = next_pos;
|
useful_keys.pop().map(|k| next.push(k));
|
||||||
for k in &dependencies.get(&next).unwrap().0 {
|
useful_keys.pop().map(|k| next.push(k));
|
||||||
dbg!(&k);
|
let len = next.len();
|
||||||
remove(k.to_owned());
|
next.par_iter()
|
||||||
i += 1;
|
.take((len.min(5) - 1).max(1))
|
||||||
|
.map(|(k, _)| {
|
||||||
|
let mut map2 = map.clone();
|
||||||
|
let next_pos = find(&map2, k.0).expect("Could not find key #3");
|
||||||
|
let steps_after_next = steps + distances.get(&next_pos).expect("No distance to key #3");
|
||||||
|
// collect keys on the way (if any)
|
||||||
|
for k in &dependencies.get(&k).expect("No dependency found").0 {
|
||||||
|
remove(&mut map2, k.to_owned());
|
||||||
}
|
}
|
||||||
remove(next);
|
remove(&mut map2, k.to_owned().to_owned());
|
||||||
i += 1;
|
next_key(&mut map2, &next_pos, steps_after_next)
|
||||||
dbg!(&i);
|
})
|
||||||
dbg!(&steps);
|
.min()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
println!("{}", steps);
|
|
||||||
|
fn main() {
|
||||||
|
let map: HashMap<Position2D, char> = io::stdin()
|
||||||
|
.lock()
|
||||||
|
.lines()
|
||||||
|
.enumerate()
|
||||||
|
.flat_map(move |(y, l)| {
|
||||||
|
l.unwrap()
|
||||||
|
.to_owned()
|
||||||
|
.chars()
|
||||||
|
.enumerate()
|
||||||
|
.map(move |(x, c)| ((x, y).into(), c))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let pos = find(&map, '@').unwrap();
|
||||||
|
let steps = 0;
|
||||||
|
let (_, dependencies, _) = traverse(&map, pos.to_owned());
|
||||||
|
let p1 = next_key(&mut map.clone(), &pos, 0);
|
||||||
|
println!("Part 1: {}", p1);
|
||||||
|
println!("Part 1: {}", BEST.lock().unwrap());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user