advent-of-code/2021/src/bin/day05.rs

87 lines
2.4 KiB
Rust
Raw Normal View History

2021-12-05 21:25:04 +01:00
#![feature(int_abs_diff)]
2021-12-05 20:48:20 +01:00
#![feature(test)]
extern crate test;
use aoc2021::common::*;
2021-12-05 22:00:14 +01:00
use fnv::{FnvHashMap, FnvHasher};
use std::hash::BuildHasherDefault;
2021-12-05 20:48:20 +01:00
const DAY: usize = 5;
2021-12-05 21:25:04 +01:00
type Coordinate = (i16, i16); // twice as fast as using i64s ¯\_(ツ)_/¯
type Parsed = Vec<(Coordinate, Coordinate)>;
2021-12-05 20:48:20 +01:00
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()
}
2021-12-05 22:00:14 +01:00
fn solve<F: FnMut(&(Coordinate, Coordinate)) -> Vec<Coordinate>>(parsed: &Parsed, capacity: usize, f: F) -> usize {
2021-12-05 20:48:20 +01:00
parsed
.iter()
2021-12-05 21:25:04 +01:00
.flat_map(f)
2021-12-05 22:00:14 +01:00
.fold(FnvHashMap::with_capacity_and_hasher(capacity, BuildHasherDefault::<FnvHasher>::default()), |mut map, c| {
2021-12-05 21:25:04 +01:00
*map.entry(c).or_insert(0) += 1;
map
2021-12-05 20:48:20 +01:00
})
2021-12-05 21:25:04 +01:00
.values()
.filter(|&&n| n > 1)
.count()
}
fn part1(parsed: &Parsed) -> usize {
2021-12-05 22:00:14 +01:00
solve(parsed, parsed.len() * 200, |&cs| match cs {
2021-12-05 21:25:04 +01:00
((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![],
})
2021-12-05 20:48:20 +01:00
}
fn part2(parsed: &Parsed) -> usize {
2021-12-05 21:25:04 +01:00
let offset = |x1, x2| (x1 < x2) as i16 - (x1 > x2) as i16;
2021-12-05 22:00:14 +01:00
solve(parsed, parsed.len() * 400, |&((mut x1, mut y1), (x2, y2))| {
2021-12-05 21:25:04 +01:00
let mut coords = Vec::with_capacity(x1.abs_diff(x2).max(y1.abs_diff(y2)) as usize + 1);
let x_offset = offset(x1, x2);
let y_offset = offset(y1, y2);
loop {
coords.push((x1, y1));
if x1 == x2 && y1 == y2 {
break;
}
x1 += x_offset;
y1 += y_offset;
}
coords
})
2021-12-05 20:48:20 +01:00
}
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);
}