aoc-2021/src/t05_hydrothermal_venture/mod.rs

144 lines
3.3 KiB
Rust
Raw Normal View History

2022-08-05 17:45:35 +00:00
use std::{
cmp::Ordering,
collections::{HashMap, HashSet},
fmt::Display,
io::{BufRead, BufReader},
};
use crate::types::TestMode;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct Point {
x: i64,
y: i64,
}
impl Display for Point {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("({}, {})", self.x, self.y))
.unwrap();
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
struct Line {
p1: Point,
p2: Point,
}
impl Display for Line {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("[{} -> {}]", self.p1, self.p2))
.unwrap();
Ok(())
}
}
impl Line {
fn points(&self) -> HashSet<Point> {
let mut res = HashSet::new();
let dx = Self::sign(self.p2.x - self.p1.x);
let dy = Self::sign(self.p2.y - self.p1.y);
let mut x = self.p1.x;
let mut y = self.p1.y;
loop {
let p = Point { x, y };
res.insert(p);
if x == self.p2.x && y == self.p2.y {
break;
}
x += dx;
y += dy;
}
res
}
fn sign(expr: i64) -> i64 {
match expr.cmp(&0) {
Ordering::Less => -1,
Ordering::Equal => 0,
Ordering::Greater => 1,
}
}
}
struct Input {
lines: Vec<Line>,
}
fn parse_input(test_mode: TestMode) -> Input {
let f = test_mode.input_file(file!());
let br = BufReader::new(f);
let lines = br
.lines()
.map(|line| {
let line = line.unwrap();
let mut s = line.split_terminator(" -> ");
let mut m = s.next().unwrap().split_terminator(',');
let p1 = Point {
x: m.next().unwrap().parse().unwrap(),
y: m.next().unwrap().parse().unwrap(),
};
let mut m = s.next().unwrap().split_terminator(',');
let p2 = Point {
x: m.next().unwrap().parse().unwrap(),
y: m.next().unwrap().parse().unwrap(),
};
Line { p1, p2 }
})
.collect();
Input { lines }
}
pub fn hydrothermal_venture_1(test_mode: TestMode) {
let input = parse_input(test_mode);
let orthogonal_lines: Vec<_> = input
.lines
.into_iter()
.filter(|line| line.p1.x == line.p2.x || line.p1.y == line.p2.y)
.collect();
let mut point_count = HashMap::<Point, i64>::new();
for line in orthogonal_lines {
for point in line.points() {
*point_count.entry(point).or_insert(0) += 1;
}
}
let num_intersections = point_count
.iter()
.filter(|point_usages| point_usages.1 > &1)
.count();
println!("{}", num_intersections);
}
pub fn hydrothermal_venture_2(test_mode: TestMode) {
let lines = parse_input(test_mode).lines;
let mut point_count = HashMap::<Point, i64>::new();
for line in lines {
for point in line.points() {
*point_count.entry(point).or_insert(0) += 1;
}
}
let num_intersections = point_count
.iter()
.filter(|point_usages| point_usages.1 > &1)
.count();
println!("{}", num_intersections);
}