129 lines
3.8 KiB
Rust
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
|
|
})
|
|
}
|