Compare commits

...

2 Commits

Author SHA1 Message Date
Johannes
241ca8ea18 day20 part1 fast 2018-12-21 10:32:11 +01:00
Johannes
a35881fb01 day20 part 1 super slow 2018-12-21 10:03:06 +01:00
2 changed files with 106 additions and 9 deletions

1
input/day20.txt Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,25 +1,55 @@
use self::Tile::*;
#[allow(unused_imports)]
use crate::utils;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::ops::Add;
use std::collections::VecDeque;
pub fn task1() {
// let input = utils::read_file("input/day20.txt");
let input = "^ENWWW(NEEE|SSE(EE|N))$".to_string();
let input = utils::read_file("input/day20.txt");
// let input = "^ENNWSWW(NEWS|)SSSEEN(WNSE|)EE(SWEN|)NNN$".to_string();
let input = &input[1..];
let mut map: HashMap<Point, Tile> = HashMap::new();
add_default_neighbors_for_room(&mut map, Point(0, 0));
parse_input(&mut map, &input, Point(0, 0));
print_map(&map);
// print_map(&map);
println!("Most distant point: {:?}", longest_shortest_path(&map, Point(0,0)));
}
fn parse_input(map: &mut HashMap<Point, Tile>, input: &str, position: Point) {
/// Returns the end points of the parsed input
fn parse_input(map: &mut HashMap<Point, Tile>, input: &str, position: Point) -> HashSet<Point> {
// println!("{}, {:?}", input, position);
if input == "$" {
println!("End of the road.");
return vec!(position).into_iter().collect();
}
let mut position = position;
let mut input = input;
while let Some(c) = input.chars().next() {
let mut iterator = input.chars();
while let Some(c) = iterator.next() {
match c {
'(' => return,
'(' => {
let (parts, rest) = split_parts(&input);
let mut middle_points: HashSet<Point> = HashSet::new();
for part in parts {
if part.len() > 0 {
for x in parse_input(map, part, position) {
middle_points.insert(x);
}
}
}
let mut end_points: HashSet<Point> = HashSet::new();
for point in middle_points {
if rest.len() > 0 {
for x in parse_input(map, rest, point) {
end_points.insert(x);
}
}
}
return end_points;
}
'N' => {
position = Point(position.0, position.1 - 2);
add_default_neighbors_for_room(map, position);
@@ -44,13 +74,50 @@ fn parse_input(map: &mut HashMap<Point, Tile>, input: &str, position: Point) {
map.insert(Point(position.0 + 1, position.1), Door);
input = &input[1..];
}
'$' => return,
'$' => break,
c => panic!(
"Stumbled upon a '{}' when reading input where it shouldn't be",
c
),
}
}
vec!(position).into_iter().collect()
}
/// Splits the input by '|', but only by those that are not enclosed by further parenthesises.
/// The second return value is the rest after the closing parenthesis
fn split_parts(input: &str) -> (Vec<&str>, &str) {
// println!("Splitting '{}'", input);
let mut count = 0;
let mut closing_index = None::<usize>;
let mut last_separator = 0;
let mut parts = Vec::new();
for (i, c) in input.chars().enumerate() {
match c {
'(' => count += 1,
')' => {
count -= 1;
if count == 0 {
closing_index = Some(i);
parts.push(&input[last_separator + 1..i]);
break;
}
}
'|' => {
// println!("| at {} (depth {})", i, count);
if count == 1 {
parts.push(&input[last_separator + 1..i]);
last_separator = i;
}
}
_ => {}
}
}
let closing_index =
closing_index.expect(&format!("No matching closing parenthesis in {}", input));
(parts, &input[closing_index + 1..])
}
fn add_default_neighbors_for_room(map: &mut HashMap<Point, Tile>, position: Point) {
@@ -82,7 +149,7 @@ fn print_map(map: &HashMap<Point, Tile>) {
None => " ",
Some(Wall) => "#",
Some(Room) => ".",
Some(Unknown) => "?",
Some(Unknown) => "#",
Some(Door) => {
if y % 2 == 0 {
"|"
@@ -98,6 +165,31 @@ fn print_map(map: &HashMap<Point, Tile>) {
}
}
fn longest_shortest_path(map: &HashMap<Point, Tile>, start: Point) -> Option<(Point, usize)> {
let mut distances: HashMap<Point, usize> = HashMap::with_capacity(map.len());
let mut open: VecDeque<(usize,Point)> = VecDeque::new();
let mut visited: HashSet<Point> = HashSet::new();
open.push_back((0,start));
visited.insert(start);
while let Some((distance, predecessor)) = open.pop_front() {
distances.insert(predecessor, distance);
for p in predecessor.neighbors() {
if let Some(Door) = map.get(&p) {
let room = predecessor.next_room(&p);
if !visited.contains(&room) {
visited.insert(room);
open.push_back((distance + 1, room));
}
}
}
}
if let Some((point, distance)) = distances.iter().max_by_key(|it| it.1) {
Some((*point, *distance))
} else {
None
}
}
#[derive(Eq, PartialEq, Hash, Clone, Copy, Debug)]
struct Point(i32, i32);
@@ -119,6 +211,10 @@ impl Point {
Point(self.0, self.1 + 1),
]
}
fn next_room(&self, other: &Self) -> Self {
Point(self.0 + 2*(other.0 - self.0), self.1 +2*(other.1-self.1))
}
}
enum Tile {