77 lines
2.4 KiB
Rust
77 lines
2.4 KiB
Rust
|
#![feature(test)]
|
||
|
extern crate test;
|
||
|
use aoc2021::common::*;
|
||
|
use fnv::FnvHashMap;
|
||
|
use itertools::Itertools;
|
||
|
use std::collections::HashMap;
|
||
|
|
||
|
const DAY: usize = 5;
|
||
|
type Parsed = Vec<((usize, usize), (usize, usize))>;
|
||
|
|
||
|
fn parse_input(raw: &str) -> Parsed {
|
||
|
raw.lines()
|
||
|
.filter_map(|line| line.split_once(" -> "))
|
||
|
.filter_map(|(c1, c2)| c1.split_once(',').zip(c2.split_once(',')))
|
||
|
.map(|((x1, y1), (x2, y2))| ((x1.parse().unwrap(), y1.parse().unwrap()), (x2.parse().unwrap(), y2.parse().unwrap())))
|
||
|
.collect()
|
||
|
}
|
||
|
|
||
|
fn part1(parsed: &Parsed) -> usize {
|
||
|
let mut map: HashMap<_, _, _> = FnvHashMap::default();
|
||
|
parsed
|
||
|
.iter()
|
||
|
.flat_map(|cs| match cs {
|
||
|
((x1, y1), (x2, y2)) if x1 == x2 => (*y1.min(y2)..=*y1.max(y2)).map(|y| (*x1, y)).collect(),
|
||
|
((x1, y1), (x2, y2)) if y1 == y2 => (*x1.min(x2)..=*x1.max(x2)).map(|x| (x, *y1)).collect(),
|
||
|
_ => vec![],
|
||
|
})
|
||
|
.for_each(|c| *map.entry(c).or_insert(0) += 1);
|
||
|
map.values().filter(|&&n| n > 1).count()
|
||
|
}
|
||
|
|
||
|
fn part2(parsed: &Parsed) -> usize {
|
||
|
let mut map: HashMap<_, _, _> = FnvHashMap::default();
|
||
|
parsed
|
||
|
.iter()
|
||
|
.flat_map(|cs| match cs {
|
||
|
((x1, y1), (x2, y2)) if x1 == x2 => (*y1.min(y2)..=*y1.max(y2)).map(|y| (*x1, y)).collect_vec(),
|
||
|
((x1, y1), (x2, y2)) if y1 == y2 => (*x1.min(x2)..=*x1.max(x2)).map(|x| (x, *y1)).collect(),
|
||
|
((x1, y1), (x2, y2)) if x1 < x2 && y1 < y2 => (*x1..=*x2).zip(*y1..=*y2).collect(),
|
||
|
((x1, y1), (x2, y2)) if x1 < x2 && y1 > y2 => (*x1..=*x2).zip((*y2..=*y1).rev()).collect(),
|
||
|
((x1, y1), (x2, y2)) if x1 > x2 && y1 < y2 => (*x2..=*x1).rev().zip(*y1..=*y2).collect(),
|
||
|
((x1, y1), (x2, y2)) if x1 > x2 && y1 > y2 => (*x2..=*x1).rev().zip((*y2..=*y1).rev()).collect(),
|
||
|
_ => unreachable!(),
|
||
|
})
|
||
|
.for_each(|c| *map.entry(c).or_insert(0) += 1);
|
||
|
map.values().filter(|&&n| n > 1).count()
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let input = parse_input(&read_file(DAY));
|
||
|
println!("Part 1: {}", part1(&input));
|
||
|
println!("Part 2: {}", part2(&input));
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
use super::*;
|
||
|
use aoc2021::*;
|
||
|
|
||
|
const TEST_INPUT: &str = "0,9 -> 5,9
|
||
|
8,0 -> 0,8
|
||
|
9,4 -> 3,4
|
||
|
2,2 -> 2,1
|
||
|
7,0 -> 7,4
|
||
|
6,4 -> 2,0
|
||
|
0,9 -> 2,9
|
||
|
3,4 -> 1,4
|
||
|
0,0 -> 8,8
|
||
|
5,5 -> 8,2";
|
||
|
|
||
|
test!(part1() == 5);
|
||
|
test!(part2() == 12);
|
||
|
bench!(part1() == 5280);
|
||
|
bench!(part2() == 16716);
|
||
|
bench_input!(Vec::len => 500);
|
||
|
}
|