From 5b65e8ec710f044e6f9b9d50eb812d4726b8d112 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Sun, 5 Dec 2021 14:43:03 -0800 Subject: [PATCH] Day 5 part 2 --- 2021/src/day5.rs | 118 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 96 insertions(+), 22 deletions(-) diff --git a/2021/src/day5.rs b/2021/src/day5.rs index 632a115..8ca5f88 100644 --- a/2021/src/day5.rs +++ b/2021/src/day5.rs @@ -1,3 +1,4 @@ +//! //! --- Day 5: Hydrothermal Venture --- //! You come across a field of hydrothermal vents on the ocean floor! These vents constantly produce large, opaque clouds, so it would be best to avoid them if possible. //! @@ -36,6 +37,29 @@ //! To avoid the most dangerous areas, you need to determine the number of points where at least two lines overlap. In the above example, this is anywhere in the diagram with a 2 or larger - a total of 5 points. //! //! Consider only horizontal and vertical lines. At how many points do at least two lines overlap? +//! +//! --- Part Two --- +//! Unfortunately, considering only horizontal and vertical lines doesn't give you the full picture; you need to also consider diagonal lines. +//! +//! Because of the limits of the hydrothermal vent mapping system, the lines in your list will only ever be horizontal, vertical, or a diagonal line at exactly 45 degrees. In other words: +//! +//! An entry like 1,1 -> 3,3 covers points 1,1, 2,2, and 3,3. +//! An entry like 9,7 -> 7,9 covers points 9,7, 8,8, and 7,9. +//! Considering all lines from the above example would now produce the following diagram: +//! +//! 1.1....11. +//! .111...2.. +//! ..2.1.111. +//! ...1.2.2.. +//! .112313211 +//! ...1.2.... +//! ..1...1... +//! .1.....1.. +//! 1.......1. +//! 222111.... +//! You still need to determine the number of points where at least two lines overlap. In the above example, this is still anywhere in the diagram with a 2 or larger - now a total of 12 points. +//! +//! Consider all of the lines. At how many points do at least two lines overlap? use std::{ fmt::{Debug, Error, Formatter}, @@ -54,7 +78,6 @@ struct Point { y: i32, } -#[derive(Debug)] struct Line { p0: Point, p1: Point, @@ -68,6 +91,16 @@ enum LineError { PrematureEOL, } +impl Debug for Line { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + writeln!( + f, + "{},{} -> {},{}", + self.p0.x, self.p0.y, self.p1.x, self.p1.y, + ) + } +} + impl FromStr for Line { type Err = LineError; @@ -113,13 +146,13 @@ impl Image { impl Index<(usize, usize)> for Image { type Output = u32; fn index(&self, (x, y): (usize, usize)) -> &Self::Output { - &self.pixels[x + y * (self.width - 1)] + &self.pixels[x + y * self.width] } } impl IndexMut<(usize, usize)> for Image { fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output { - &mut self.pixels[x + y * (self.width - 1)] + &mut self.pixels[x + y * self.width] } } @@ -128,7 +161,12 @@ impl Debug for Image { writeln!(f, "({}, {})", self.width, self.height)?; for y in 0..self.height { for x in 0..self.width { - write!(f, "{:2}", self[(x, y)])?; + let v = self[(x, y)]; + if v == 0 { + write!(f, ".")?; + } else { + write!(f, "{}", v)?; + } } writeln!(f)?; } @@ -146,8 +184,8 @@ fn parse(input: &str) -> Result> { } fn draw(im: &mut Image, l: &Line) { - let dx = l.p0.x - l.p1.x; - let dy = l.p0.y - l.p1.y; + let dx = l.p1.x - l.p0.x; + let dy = l.p1.y - l.p0.y; if dx == 0 { let x = l.p0.x as usize; @@ -157,8 +195,7 @@ fn draw(im: &mut Image, l: &Line) { for y in sy..=ey { im[(x, y as usize)] += 1; } - } - if dy == 0 { + } else if dy == 0 { let y = l.p0.y as usize; let sx = l.p0.x; let ex = l.p1.x; @@ -166,6 +203,20 @@ fn draw(im: &mut Image, l: &Line) { for x in sx..=ex { im[(x as usize, y)] += 1; } + } else { + // We only support 45 degree angles. + assert_eq!(dx.abs(), dy.abs()); + let dx = dx / dx.abs(); + let dy = dy / dy.abs(); + + let mut x = l.p0.x; + let mut y = l.p0.y; + while x != l.p1.x && y != l.p1.y { + im[(x as usize, y as usize)] += 1; + x += dx; + y += dy; + } + im[(x as usize, y as usize)] += 1; } } @@ -175,12 +226,14 @@ fn part1(lines: &[Line]) -> Result { .iter() .map(|l| l.p0.x.max(l.p1.x) as usize) .max() - .expect("couldn't find max width"); + .expect("couldn't find max width") + + 1; let height = lines .iter() .map(|l| l.p0.y.max(l.p1.y) as usize) .max() - .expect("couldn't find max height"); + .expect("couldn't find max height") + + 1; let mut im = Image::new(width, height); for l in lines .iter() @@ -191,13 +244,26 @@ fn part1(lines: &[Line]) -> Result { Ok(im.answer()) } -/* #[aoc(day5, part2)] -fn part2(depths: &[u32]) -> Result { -todo!("part2") -Ok(()) +fn part2(lines: &[Line]) -> Result { + let width = lines + .iter() + .map(|l| l.p0.x.max(l.p1.x) as usize) + .max() + .expect("couldn't find max width") + + 1; + let height = lines + .iter() + .map(|l| l.p0.y.max(l.p1.y) as usize) + .max() + .expect("couldn't find max height") + + 1; + let mut im = Image::new(width, height); + for l in lines { + draw(&mut im, l); + } + Ok(im.answer()) } -*/ #[cfg(test)] mod tests { @@ -222,14 +288,22 @@ mod tests { Ok(()) } - /* #[test] - fn test_part2()->Result<()> { - let input = r#" + fn test_part2() -> Result<()> { + let input = r#" +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 "# - .trim(); - assert_eq!(part2(&parse(input)?)?, TODO); - Ok(()) + .trim(); + assert_eq!(part2(&parse(input)?)?, 12); + Ok(()) } - */ }