Files
aoc_2019/src/tasks/day03.rs
2019-12-04 20:35:24 +01:00

129 lines
3.8 KiB
Rust

use std::collections::{HashMap, HashSet};
use std::fs;
use std::iter;
#[allow(dead_code)]
pub fn run() {
let content = fs::read_to_string("input/day03.txt").unwrap();
let p1: Vec<&str> = content.lines().next().unwrap().split(",").collect();
let p2: Vec<&str> = content.lines().skip(1).next().unwrap().split(",").collect();
task1(&p1, &p2);
task2(&p1, &p2);
}
fn task1(p1: &Vec<&str>, p2: &Vec<&str>) {
let points1 = visited_points(&p1);
let points2 = visited_points(&p2);
let closest_distance = points1
.intersection(&points2)
.min_by_key(|(a, b)| a.abs() + b.abs())
.unwrap();
println!(
"Task 1: Closest point is at distance {}",
closest_distance.0.abs() + closest_distance.1.abs()
);
}
/**
* returns all visited points, the origin is left out, unless it is visited once again
*/
fn visited_points(p: &Vec<&str>) -> HashSet<(i32, i32)> {
p.iter()
.map(|step| {
let direction = step.chars().next().unwrap();
let number = step[1..].parse::<i32>().unwrap();
(direction, number)
})
.scan((0, 0), |(cx, cy), (direction, number)| {
fn fi(i: i32) -> i32 {
i + 1
}
fn fd(i: i32) -> i32 {
i - 1
}
let fstep = match direction {
'U' | 'R' => fi,
'D' | 'L' => fd,
_ => panic!("Unexpected input"),
};
fn fx(point: (i32, i32), f: fn(i32) -> i32) -> (i32, i32) {
let (x, y) = point;
(f(x), y)
}
fn fy(point: (i32, i32), f: fn(i32) -> i32) -> (i32, i32) {
let (x, y) = point;
(x, f(y))
}
let faxis = match direction {
'U' | 'D' => fy,
'R' | 'L' => fx,
_ => panic!("Unexpected input"),
};
let steps = (0..number)
.scan((*cx, *cy), |(sx, sy), _| {
let (newx, newy) = faxis((*sx, *sy), fstep);
*sx = newx;
*sy = newy;
Some((newx, newy))
})
.collect::<Vec<(i32, i32)>>();
let last = steps.iter().last().unwrap();
*cx = last.0;
*cy = last.1;
Some(steps)
})
.flatten()
.collect()
}
fn task2(p1: &Vec<&str>, p2: &Vec<&str>) {
let points1 = get_points(&p1);
let points2 = get_points(&p2);
let set1 = points1
.keys()
.map(|(x, y)| (*x, *y))
.collect::<HashSet<(i32, i32)>>();
let set2 = points2
.keys()
.map(|(x, y)| (*x, *y))
.collect::<HashSet<(i32, i32)>>();
let p = set1
.intersection(&set2)
.min_by_key(|p| points1[p] + points2[p])
.unwrap();
println!(
"Task 2: shortest is at {:?} with distances {}/{} = {}",
p,
points1[p],
points2[p],
points1[p] + points2[p]
);
// 20384 is too short
}
fn get_points(path: &Vec<&str>) -> HashMap<(i32, i32), usize> {
let directions = vec![('U', (0, 1)), ('D', (0, -1)), ('L', (-1, 0)), ('R', (1, 0))]
.into_iter()
.collect::<HashMap<_, _>>();
path.iter()
.map(|it| {
let direction = it.chars().next().unwrap();
let number = it[1..].parse::<usize>().unwrap();
iter::repeat(direction).take(number)
})
.flatten()
.scan((0, 0), |(sx, sy), dir| {
let (dx, dy) = directions[&dir];
*sx += dx;
*sy += dy;
Some((*sx, *sy))
})
.enumerate()
.fold(HashMap::new(), |mut hm, (i, point)| {
if !hm.contains_key(&point) {
hm.insert(point, i + 1);
}
hm
})
}