still WIP D18
This commit is contained in:
parent
4a28ac8e8e
commit
26a9254d73
|
@ -0,0 +1,9 @@
|
|||
#################
|
||||
#i.G..c...e..H.p#
|
||||
########.########
|
||||
#j.A..b...f..D.o#
|
||||
########@########
|
||||
#k.E..a...g..B.n#
|
||||
########.########
|
||||
#l.F..d...h..C.m#
|
||||
#################
|
|
@ -0,0 +1,6 @@
|
|||
########################
|
||||
#@..............ac.GI.b#
|
||||
###d#e#f################
|
||||
###A#B#C################
|
||||
###g#h#i################
|
||||
########################
|
|
@ -0,0 +1,5 @@
|
|||
########################
|
||||
#...............b.C.D.f#
|
||||
#.######################
|
||||
#.....@.a.B.c.d.A.e.F.g#
|
||||
########################
|
|
@ -9,3 +9,6 @@ tasks:
|
|||
dead end detection -> also done?
|
||||
//implement pathfinding (maybe dijkstra-like?)
|
||||
|
||||
|
||||
4816 too high
|
||||
4266 too high
|
||||
|
|
|
@ -1,49 +1,71 @@
|
|||
use grid::*;
|
||||
use std::char;
|
||||
use std::collections::{HashMap,HashSet};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::io::{self, BufRead};
|
||||
use std::sync::Mutex;
|
||||
use std::ops::Mul;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Clone, Debug)]
|
||||
struct Door(char);
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Clone, Debug)]
|
||||
struct Key(char);
|
||||
|
||||
lazy_static! {
|
||||
static ref MAP: HashMap<Position2D, char> = io::stdin()
|
||||
.lock()
|
||||
.lines()
|
||||
.enumerate()
|
||||
.flat_map(move |(y, l)| l
|
||||
.unwrap()
|
||||
.to_owned()
|
||||
.chars()
|
||||
static ref MAP: Mutex<HashMap<Position2D, char>> = Mutex::new(
|
||||
io::stdin()
|
||||
.lock()
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(move |(x, c)| ((x, y).into(), c))
|
||||
.collect::<Vec<_>>())
|
||||
.collect();
|
||||
.flat_map(move |(y, l)| l
|
||||
.unwrap()
|
||||
.to_owned()
|
||||
.chars()
|
||||
.enumerate()
|
||||
.map(move |(x, c)| ((x, y).into(), c))
|
||||
.collect::<Vec<_>>())
|
||||
.collect()
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_neighbors(position: Position2D, steps: usize, distances: &mut HashMap<Position2D, usize>, dependencies: &mut HashMap<char, HashSet<char>>, mut doors: HashSet<char>) {
|
||||
fn get(p: &Position2D) -> Option<char> {
|
||||
MAP.lock().unwrap().get(p).copied()
|
||||
}
|
||||
|
||||
fn visit_neighbors(
|
||||
position: Position2D,
|
||||
steps: usize,
|
||||
distances: &mut HashMap<Position2D, usize>,
|
||||
dependencies: &mut HashMap<Key, (HashSet<Key>, HashSet<Door>)>,
|
||||
door_dependencies: &mut HashMap<Door, HashSet<Door>>,
|
||||
mut doors: HashSet<Door>,
|
||||
mut keys: HashSet<Key>,
|
||||
) {
|
||||
let c = get(&position).unwrap();
|
||||
if c.is_alphabetic() {
|
||||
if c.is_lowercase() {
|
||||
dependencies.insert(Key { 0: c }, (keys.clone(), doors.clone()));
|
||||
keys.insert(Key { 0: c });
|
||||
}
|
||||
if c.is_uppercase() {
|
||||
door_dependencies.insert(Door { 0: c }, doors.clone());
|
||||
doors.insert(Door { 0: c });
|
||||
}
|
||||
}
|
||||
let mut unvisited = Vec::new();
|
||||
// TODO: fix ownership and make this a single filter().inspect().for_each()
|
||||
for (_, p) in &position.neighbors() {
|
||||
match MAP.get(p) {
|
||||
Some(&'#') => (),
|
||||
Some(n) if n.is_alphanumeric() => {
|
||||
if n.is_lowercase() {
|
||||
dependencies.insert(*n, doors.clone());
|
||||
}
|
||||
if n.is_uppercase() {
|
||||
doors.insert(*n);
|
||||
}
|
||||
if distances.get(p).is_none() {
|
||||
unvisited.push(p.to_owned());
|
||||
}
|
||||
},
|
||||
match get(p) {
|
||||
Some('#') => (),
|
||||
_ => {
|
||||
if distances.get(p).is_none() {
|
||||
unvisited.push(p.to_owned());
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
if MAP.get(p) != Some(&'#') && distances.get(p).is_none() {
|
||||
if get(p) != Some('#') && distances.get(p).is_none() {
|
||||
unvisited.push(p.to_owned());
|
||||
}
|
||||
}
|
||||
|
@ -53,31 +75,135 @@ fn visit_neighbors(position: Position2D, steps: usize, distances: &mut HashMap<P
|
|||
.for_each(|p| visit_neighbors(p.to_owned(), steps+1, distances));
|
||||
*/
|
||||
for p in &unvisited {
|
||||
distances.insert(p.to_owned(), steps+1);
|
||||
distances.insert(p.to_owned(), steps + 1);
|
||||
}
|
||||
for p in &unvisited {
|
||||
visit_neighbors(p.to_owned(), steps+1, distances, dependencies, doors.clone());
|
||||
visit_neighbors(
|
||||
p.to_owned(),
|
||||
steps + 1,
|
||||
distances,
|
||||
dependencies,
|
||||
door_dependencies,
|
||||
doors.clone(),
|
||||
keys.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn traverse(start: Position2D) -> (HashMap<Position2D, usize>, HashMap<char, HashSet<char>>) {
|
||||
fn traverse(
|
||||
start: Position2D,
|
||||
) -> (
|
||||
HashMap<Position2D, usize>,
|
||||
HashMap<Key, (HashSet<Key>, HashSet<Door>)>,
|
||||
HashMap<Door, HashSet<Door>>,
|
||||
) {
|
||||
let mut distances = HashMap::new();
|
||||
let mut dependencies = HashMap::new();
|
||||
let mut door_dependencies = HashMap::new();
|
||||
distances.insert(start, 0usize);
|
||||
visit_neighbors(start, 0, &mut distances, &mut dependencies, HashSet::new());
|
||||
(distances, dependencies)
|
||||
visit_neighbors(
|
||||
start,
|
||||
0,
|
||||
&mut distances,
|
||||
&mut dependencies,
|
||||
&mut door_dependencies,
|
||||
HashSet::new(),
|
||||
HashSet::new(),
|
||||
);
|
||||
(distances, dependencies, door_dependencies)
|
||||
}
|
||||
|
||||
fn find_keys_at_dead_ends(deps: &HashMap<Key, (HashSet<Key>, HashSet<Door>)>) -> HashSet<Key> {
|
||||
let keydeps: HashSet<_> = deps.iter().flat_map(|(_, (keys, _))| keys).collect();
|
||||
deps.keys()
|
||||
.collect::<HashSet<_>>()
|
||||
.difference(&keydeps)
|
||||
.into_iter()
|
||||
.map(|k| k.to_owned().to_owned())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn find(c: char) -> Option<Position2D> {
|
||||
let map = MAP.lock().unwrap();
|
||||
map.keys().find(|p| map.get(&p) == Some(&c)).copied()
|
||||
}
|
||||
|
||||
fn clear_field(p: &Position2D) {
|
||||
MAP.lock().unwrap().insert(*p, '.');
|
||||
}
|
||||
|
||||
fn remove(k: Key) {
|
||||
let key_pos = find(k.0).unwrap();
|
||||
clear_field(&key_pos);
|
||||
if let Some(door_pos) = find(k.0.to_uppercase().next().unwrap()) {
|
||||
clear_field(&door_pos);
|
||||
}
|
||||
}
|
||||
|
||||
fn distance_to_door(k: &Key) -> usize {
|
||||
let (distances, _, _) = traverse(find(k.0).unwrap());
|
||||
let door_pos = find(k.0.to_uppercase().next().unwrap());
|
||||
*door_pos.map(|p| distances.get(&p).unwrap()).unwrap_or(&10)
|
||||
}
|
||||
fn distance_to_locked_door(k: &Key) -> usize {
|
||||
let (distances, _, doors) = traverse(find(k.0).unwrap());
|
||||
*doors.keys()
|
||||
.map(|d| find(d.0).unwrap())
|
||||
.map(|p| distances.get(&p).unwrap_or(&9999999999999))
|
||||
.min()
|
||||
.unwrap_or(&0)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
//println!("{:?}", MAP.keys());
|
||||
println!("{}", draw_ascii(&MAP, ' '));
|
||||
let start = MAP.keys().find(|p| MAP.get(&p) == Some(&'@')).unwrap();
|
||||
let v = MAP.keys().find(|p| MAP.get(&p) == Some(&'v')).unwrap();
|
||||
println!("Start: {:?}", start);
|
||||
let (distances, dependencies) = traverse(start.to_owned());
|
||||
println!("{:?}", distances);
|
||||
println!("{:?}", distances.get(&v));
|
||||
println!("{:?}", distances.len());
|
||||
println!("{:?}", dependencies.get(&'m'));
|
||||
println!("{}", dependencies.len());
|
||||
let mut pos = find('@').unwrap();
|
||||
let mut steps = 0;
|
||||
let (_, dependencies, _) = traverse(pos.to_owned());
|
||||
let mut i = 0;
|
||||
while i < dependencies.len() {
|
||||
println!("{}", i);
|
||||
let (distances, dependencies, door_dependencies) = traverse(pos.to_owned());
|
||||
//dbg!(distances.get(&find('c').unwrap()));
|
||||
|
||||
let reachable_doors: HashSet<_> = door_dependencies
|
||||
.iter()
|
||||
.filter_map(|(door, doors)| if doors.is_empty() { Some(door) } else { None })
|
||||
.collect();
|
||||
let useful_keys = dependencies
|
||||
.iter()
|
||||
.filter(|(_, (_, d))| d.is_empty())
|
||||
.filter(|(k, _)| {
|
||||
reachable_doors.contains(&Door {
|
||||
0: k.0.to_uppercase().next().unwrap(),
|
||||
})
|
||||
})
|
||||
//.min_by_key(|(k, _)| distances.get(&find(k.0).unwrap()))
|
||||
//.unwrap()
|
||||
.map(|(k, _)| (k, distances.get(&find(k.0).unwrap()).unwrap().mul(2)));
|
||||
//.min_by_key(|k| )
|
||||
|
||||
let next: Key = find_keys_at_dead_ends(&dependencies)
|
||||
.iter()
|
||||
.filter(|k| dependencies.get(k).unwrap().1.is_empty())
|
||||
.map(|k| (k, distances.get(&find(k.0).unwrap()).unwrap().mul(1)))
|
||||
//.min_by_key(|k| distances.get(&find(k.0).unwrap()))
|
||||
.chain(useful_keys)
|
||||
.min_by_key(|(k, n)| *n)// + distance_to_locked_door(&k))// * 100 + k.0 as usize)
|
||||
.expect("no candidate found")
|
||||
.0
|
||||
.to_owned();
|
||||
dbg!(&next);
|
||||
let next_pos = find(next.0).unwrap();
|
||||
steps += distances.get(&next_pos).unwrap();
|
||||
pos = next_pos;
|
||||
for k in &dependencies.get(&next).unwrap().0 {
|
||||
dbg!(&k);
|
||||
remove(k.to_owned());
|
||||
i += 1;
|
||||
}
|
||||
remove(next);
|
||||
i += 1;
|
||||
dbg!(&i);
|
||||
dbg!(&steps);
|
||||
}
|
||||
println!("{}", steps);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user