at least part 2 was easy
This commit is contained in:
parent
444a7f6e47
commit
2269a7e086
153
2021/src/day5.rs
153
2021/src/day5.rs
@ -1,77 +1,150 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use color_eyre::eyre;
|
||||
use num::{Integer, integer::gcd};
|
||||
use num::integer::gcd;
|
||||
|
||||
use crate::lib::{ParseLines, IterExt};
|
||||
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
struct Point {
|
||||
x: isize,
|
||||
y: isize,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Line {
|
||||
start: Point,
|
||||
end: Point,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Slope {
|
||||
rise: isize,
|
||||
run: isize,
|
||||
}
|
||||
|
||||
impl Slope {
|
||||
fn apply_to(&self, pt: Point) -> Point {
|
||||
Point {
|
||||
x: pt.x + self.run,
|
||||
y: pt.y + self.rise,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Line {
|
||||
start: Point,
|
||||
end: Point,
|
||||
}
|
||||
|
||||
impl Line {
|
||||
fn slope(&self) -> Slope {
|
||||
let mut rise = self.end.y - self.start.y;
|
||||
let mut run = self.end.x - self.start.x;
|
||||
if rise != 0 && run != 0 {
|
||||
let divisor = gcd(rise, run);
|
||||
rise /= divisor;
|
||||
run /= divisor;
|
||||
let dx = self.end.y - self.start.y;
|
||||
let dy = self.end.x - self.start.x;
|
||||
|
||||
let divisor;
|
||||
if dx == 0 || dy == 0 {
|
||||
divisor = (dx + dy).abs();
|
||||
}
|
||||
else {
|
||||
divisor = gcd(dx, dy);
|
||||
}
|
||||
|
||||
Slope {
|
||||
rise: dx / divisor,
|
||||
run: dy / divisor,
|
||||
}
|
||||
}
|
||||
|
||||
fn points(&self) -> PointsIter {
|
||||
PointsIter {
|
||||
line: self,
|
||||
pos: self.start,
|
||||
slope: self.slope(),
|
||||
}
|
||||
Slope {rise, run}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PointsIter<'a> {
|
||||
line: &'a Line,
|
||||
pos: Point,
|
||||
slope: Slope,
|
||||
}
|
||||
|
||||
impl PointsIter<'_> {
|
||||
fn from(line: &Line) -> Self {
|
||||
PointsIter {
|
||||
line,
|
||||
pos: line.start,
|
||||
slope: line.slope(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for PointsIter {
|
||||
impl Iterator for PointsIter<'_> {
|
||||
type Item = Point;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.pos.x = self.line.start.x && self.pos.y == self.line.start.y {
|
||||
return Some(self.pos);
|
||||
}
|
||||
|
||||
if self.pos.x != self.line.end.x && self.pos.y != self.line.end.y {
|
||||
self.pos.y += self.slope.rise;
|
||||
self.pos.x += self.slope.run;
|
||||
return Some(self.pos);
|
||||
}
|
||||
else {
|
||||
// note, this approach will break if total dX and dY are not multiples of rise/run
|
||||
if self.pos == self.slope.apply_to(self.line.end) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let orig = self.pos;
|
||||
self.pos = self.slope.apply_to(self.pos);
|
||||
Some(orig)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct GridCounter<const W: usize, const H: usize> {
|
||||
rows: [[usize; W]; H],
|
||||
impl FromStr for Line {
|
||||
type Err = eyre::Report;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let (p1, p2) = s.split(" -> ").take_pair()?;
|
||||
let (x1, y1) = p1.split(',').take_pair()?;
|
||||
let (x2, y2) = p2.split(',').take_pair()?;
|
||||
|
||||
let start = Point {
|
||||
x: x1.parse::<isize>()?,
|
||||
y: y1.parse::<isize>()?,
|
||||
};
|
||||
let end = Point {
|
||||
x: x2.parse::<isize>()?,
|
||||
y: y2.parse::<isize>()?,
|
||||
};
|
||||
|
||||
Ok(Line {start, end})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn part1(lines: &[Line]) -> usize {
|
||||
let mut grid = vec![[0; 1000]; 1000];
|
||||
|
||||
let points = lines.iter()
|
||||
.filter(|l| l.start.x == l.end.x || l.start.y == l.end.y)
|
||||
.flat_map(|l| l.points());
|
||||
|
||||
for pt in points {
|
||||
grid[pt.y as usize][pt.x as usize] += 1;
|
||||
}
|
||||
|
||||
grid.into_iter()
|
||||
.flat_map(|row| row.into_iter())
|
||||
.filter(|n| *n > 1)
|
||||
.count()
|
||||
}
|
||||
|
||||
|
||||
fn part2(lines: &[Line]) -> usize {
|
||||
let mut grid = vec![[0; 1000]; 1000];
|
||||
|
||||
for pt in lines.iter().flat_map(|l| l.points()) {
|
||||
grid[pt.y as usize][pt.x as usize] += 1;
|
||||
}
|
||||
|
||||
grid.into_iter()
|
||||
.flat_map(|row| row.into_iter())
|
||||
.filter(|n| *n > 1)
|
||||
.count()
|
||||
}
|
||||
|
||||
|
||||
pub fn run(data: &str) -> eyre::Result<(usize, usize)> {
|
||||
let mut lines = Vec::new();
|
||||
for line in data.parse_lines::<Line>() {
|
||||
lines.push(line?);
|
||||
}
|
||||
|
||||
Ok((part1(&lines), part2(&lines)))
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use std::str::FromStr;
|
||||
use std::fs::File;
|
||||
|
||||
use color_eyre::{eyre};
|
||||
use eyre::eyre;
|
||||
|
||||
|
||||
pub fn load(filename: &str) -> eyre::Result<String> {
|
||||
@ -52,3 +53,19 @@ impl ParseLines for String {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait IterExt: Iterator {
|
||||
fn take_pair(&mut self) -> eyre::Result<(Self::Item, Self::Item)> {
|
||||
let a = match self.next() {
|
||||
Some(v) => v,
|
||||
None => return Err(eyre!("Not enough values to unpack")),
|
||||
};
|
||||
let b = match self.next() {
|
||||
Some(v) => v,
|
||||
None => return Err(eyre!("Not enough values to unpack")),
|
||||
};
|
||||
Ok((a, b))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator> IterExt for I {}
|
||||
|
@ -4,14 +4,14 @@ use color_eyre::eyre;
|
||||
|
||||
mod lib;
|
||||
use lib::load;
|
||||
mod day4;
|
||||
mod day5;
|
||||
|
||||
|
||||
fn main() -> eyre::Result<()> {
|
||||
let data = load("data/04.txt")?;
|
||||
let data = load("data/05.txt")?;
|
||||
|
||||
let start = Instant::now();
|
||||
let (one, two) = day4::run(&data)?;
|
||||
let (one, two) = day5::run(&data)?;
|
||||
let (dur, unit) = format_ns(start.elapsed().as_nanos());
|
||||
|
||||
let precision = 2.0 - dur.log10().floor();
|
||||
|
Loading…
x
Reference in New Issue
Block a user