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 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 {
|
struct Point {
|
||||||
x: isize,
|
x: isize,
|
||||||
y: isize,
|
y: isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct Line {
|
|
||||||
start: Point,
|
|
||||||
end: Point,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
struct Slope {
|
struct Slope {
|
||||||
rise: isize,
|
rise: isize,
|
||||||
run: 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 {
|
impl Line {
|
||||||
fn slope(&self) -> Slope {
|
fn slope(&self) -> Slope {
|
||||||
let mut rise = self.end.y - self.start.y;
|
let dx = self.end.y - self.start.y;
|
||||||
let mut run = self.end.x - self.start.x;
|
let dy = self.end.x - self.start.x;
|
||||||
if rise != 0 && run != 0 {
|
|
||||||
let divisor = gcd(rise, run);
|
let divisor;
|
||||||
rise /= divisor;
|
if dx == 0 || dy == 0 {
|
||||||
run /= divisor;
|
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> {
|
struct PointsIter<'a> {
|
||||||
line: &'a Line,
|
line: &'a Line,
|
||||||
pos: Point,
|
pos: Point,
|
||||||
slope: Slope,
|
slope: Slope,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointsIter<'_> {
|
impl Iterator for PointsIter<'_> {
|
||||||
fn from(line: &Line) -> Self {
|
|
||||||
PointsIter {
|
|
||||||
line,
|
|
||||||
pos: line.start,
|
|
||||||
slope: line.slope(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for PointsIter {
|
|
||||||
type Item = Point;
|
type Item = Point;
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.pos.x = self.line.start.x && self.pos.y == self.line.start.y {
|
// note, this approach will break if total dX and dY are not multiples of rise/run
|
||||||
return Some(self.pos);
|
if self.pos == self.slope.apply_to(self.line.end) {
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let orig = self.pos;
|
||||||
|
self.pos = self.slope.apply_to(self.pos);
|
||||||
|
Some(orig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct GridCounter<const W: usize, const H: usize> {
|
impl FromStr for Line {
|
||||||
rows: [[usize; W]; H],
|
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 std::fs::File;
|
||||||
|
|
||||||
use color_eyre::{eyre};
|
use color_eyre::{eyre};
|
||||||
|
use eyre::eyre;
|
||||||
|
|
||||||
|
|
||||||
pub fn load(filename: &str) -> eyre::Result<String> {
|
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;
|
mod lib;
|
||||||
use lib::load;
|
use lib::load;
|
||||||
mod day4;
|
mod day5;
|
||||||
|
|
||||||
|
|
||||||
fn main() -> eyre::Result<()> {
|
fn main() -> eyre::Result<()> {
|
||||||
let data = load("data/04.txt")?;
|
let data = load("data/05.txt")?;
|
||||||
|
|
||||||
let start = Instant::now();
|
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 (dur, unit) = format_ns(start.elapsed().as_nanos());
|
||||||
|
|
||||||
let precision = 2.0 - dur.log10().floor();
|
let precision = 2.0 - dur.log10().floor();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user