extern crate advent_of_code_2018;
use advent_of_code_2018::*;
use std::error::Error;
use std::path::PathBuf;
use std::collections::{HashSet, HashMap};
// cargo watch -cs "cargo run --release --bin day_20"
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Dir {
N, S, E, W
}
#[derive(Debug)]
struct Room {
doors: HashSet
}
impl Room {
fn new() -> Room {
Room {
doors: HashSet::new()
}
}
}
fn main() -> Result<(), Box> {
let input = &read_file(&PathBuf::from("inputs/20.txt"))?[0];
println!("Input: {:?}", input);
let rooms = populate_rooms(input);
let distances = distance_map(&rooms);
debug!(distance_to_furthest_room(&distances));
debug!(distances_more_than_1000(&distances));
Ok(())
}
fn populate_rooms(input: &str) -> HashMap<(i32, i32), Room> {
let mut rooms: HashMap<(i32, i32), Room> = HashMap::new();
rooms.insert((0,0), Room::new());
let mut coords = vec!((0, 0));
let mut coord_stack: Vec<(Vec<(i32, i32)>, Vec<(i32, i32)>)> = Vec::new();
for c in input.chars() {
match c {
'^' | '$' => {},
'E' => {
for coord in &mut coords {
rooms.get_mut(coord).unwrap().doors.insert(Dir::E);
coord.0 += 1;
rooms.entry(*coord).or_insert(Room::new());
}
},
'W' => {
for coord in &mut coords {
rooms.get_mut(coord).unwrap().doors.insert(Dir::W);
coord.0 -= 1;
rooms.entry(*coord).or_insert(Room::new());
}
},
'N' => {
for coord in &mut coords {
rooms.get_mut(coord).unwrap().doors.insert(Dir::N);
coord.1 -= 1;
rooms.entry(*coord).or_insert(Room::new());
}
},
'S' => {
for coord in &mut coords {
rooms.get_mut(coord).unwrap().doors.insert(Dir::S);
coord.1 += 1;
rooms.entry(*coord).or_insert(Room::new());
}
},
'(' => {
coord_stack.push((coords.clone(), Vec::new()));
},
'|' => {
coord_stack.last_mut().unwrap().1.append(&mut coords);
coords = coord_stack.last().unwrap().0.clone();
},
')' => {
coord_stack.last_mut().unwrap().1.append(&mut coords);
coords = coord_stack.pop().unwrap().1;
coords.sort();
coords.dedup();
},
c => {
panic!("Unknown character {}", c);
}
}
}
debug!(rooms.len());
rooms
}
fn distance_map(rooms: &HashMap<(i32, i32), Room>) -> HashMap<(i32, i32), u32> {
let mut distances: HashMap<(i32, i32), u32> = HashMap::new();
distances.insert((0,0), 0);
while distances.len() < rooms.len() {
let current_max = *distances.values().max().unwrap();
let new_distances = distances.iter()
.filter(|(_, &d)| d == current_max)
.flat_map(|(&coord, _)| {
let room = rooms.get(&coord).unwrap();
room.doors.iter().map(|dir| match dir {
Dir::N => (coord.0, coord.1-1),
Dir::S => (coord.0, coord.1+1),
Dir::W => (coord.0-1, coord.1),
Dir::E => (coord.0+1, coord.1)
}).collect::>()
})
.collect::>();
for coord in new_distances {
distances.entry(coord).or_insert(current_max + 1);
}
}
distances
}
fn distance_to_furthest_room(distances: &HashMap<(i32, i32), u32>) -> u32 {
distances.values().max().unwrap().clone()
}
fn distances_more_than_1000(distances: &HashMap<(i32, i32), u32>) -> u32 {
distances.values().filter(|&&x| x >= 1000).count() as u32
}