From b9c3ebc7d7fc9d821bfa40a1ec00963039c69ffb Mon Sep 17 00:00:00 2001 From: kageru Date: Sun, 10 Dec 2023 21:50:02 +0100 Subject: [PATCH] add 2023/10/2 --- 2023/src/bin/day10.rs | 95 ++++++++++++++++++++++++++++++++++++++----- 2023/src/direction.rs | 18 +++++++- 2023/src/position.rs | 10 ++++- 2023/src/teststuff.rs | 4 +- 4 files changed, 113 insertions(+), 14 deletions(-) diff --git a/2023/src/bin/day10.rs b/2023/src/bin/day10.rs index bc0df80..58cb4a8 100644 --- a/2023/src/bin/day10.rs +++ b/2023/src/bin/day10.rs @@ -1,5 +1,6 @@ #![feature(test)] extern crate test; +use fnv::FnvHashSet as HashSet; use std::mem::transmute; use aoc2023::{ @@ -41,14 +42,14 @@ impl Pipe { } type Parsed<'a> = (Pos, Vec<&'a [Pipe]>); -type Pos = Position2D; +type Pos = Position2D; fn parse_input(raw: &str) -> Parsed { let grid = raw.lines().rev().map(|l| unsafe { transmute::<&str, &[Pipe]>(l) }).collect_vec(); let start = grid .iter() - .enumerate() - .find_map(|(y, line)| line.iter().enumerate().find_map(|(x, p)| (*p == Pipe::Start).then_some(PositionND([x, y])))) + .zip(0..) + .find_map(|(line, y)| line.iter().zip(0..).find_map(|(p, x)| (*p == Pipe::Start).then_some(PositionND([x, y])))) .unwrap(); (start, grid) } @@ -66,24 +67,71 @@ fn part1((start, grid): &Parsed) -> usize { ALL_DIRECTIONS .iter() .cloned() - .map(|mut dir| { + .filter_map(|mut dir| { let mut pos = *start; let mut steps = 0; loop { steps += 1; pos = step(pos, dir); if &pos == start { - return steps / 2; + return Some(steps / 2); } - dir = *grid[pos.0[1]][pos.0[0]].openings().iter().find(|&&o| o != !dir).unwrap(); + dir = *grid.get(pos.0[1] as usize)?.get(pos.0[0] as usize)?.openings().iter().find(|&&o| o != !dir).unwrap(); } }) .max() .unwrap() } -fn part2(parsed: &Parsed) -> usize { - unimplemented!() +fn part2((start, grid): &Parsed) -> usize { + let mut corners = Vec::new(); + let mut dir = Direction::Down; // I got this from my part 1 solution. + let mut pos = *start; + let mut points = HashSet::default(); + loop { + pos = step(pos, dir); + let pipe = grid[pos.0[1] as usize][pos.0[0] as usize]; + points.insert(pos); + if matches!(pipe, Pipe::Start | Pipe::TopLeft | Pipe::TopRight | Pipe::BottomLeft | Pipe::BottomRight) { + corners.push(pos); + } + if &pos == start { + break; + } + dir = *pipe.openings().iter().find(|&&o| o != !dir).unwrap(); + } + let ylen = grid.len() as isize; + let xlen = grid[0].len() as isize; + (0..ylen) + .flat_map(|y| (0..xlen).map(move |x| PositionND([x, y]))) + .filter(|p| !points.contains(p)) + .filter(|p| is_inside(p, &corners)) + .count() +} + +fn is_inside(p: &Pos, polygon: &Vec) -> bool { + let mut counter = 0; + let mut p1 = polygon[0]; + let mut p2; + for i in 1..=polygon.len() { + p2 = polygon[i % polygon.len()]; + if p[1] > p1[1].min(p2[1]) { + if p[1] <= p1[1].max(p2[1]) { + if p[0] <= p1[0].max(p2[0]) { + if p1[1] != p2[1] { + let xinters = (p[1] - p1[1]) * (p2[0] - p1[0]) / (p2[1] - p1[1]) + p1[0]; + if p1[0] == p2[0] || p[0] <= xinters { + counter += 1; + } + } + } + } + } + p1 = p2; + } + + println!("Counter for {p:?} was {counter}"); + return counter % 2 != 0; } boilerplate! { @@ -95,9 +143,36 @@ L|7|| L|-JF", tests: { part1: { TEST_INPUT => 4 }, - part2: { TEST_INPUT => 0 }, + part2: { + INPUT_P2 => 4, + INPUT_P2_2 => 10, + }, }, bench1 == 6923, - bench2 == 0, + bench2 == 529, bench_parse: |p: &Parsed| (p.0, p.1.len()) => (PositionND([114, 117]), 140), } + +#[cfg(test)] +const INPUT_P2: &str = "\ +.......... +.S------7. +.|F----7|. +.||....||. +.||....||. +.|L-7F-J|. +.|..||..|. +.L--JL--J. +.........."; +#[cfg(test)] +const INPUT_P2_2: &str = "\ +FF7FSF7F7F7F7F7F---7 +L|LJ||||||||||||F--J +FL-7LJLJ||||||LJL-77 +F--JF--7||LJLJIF7FJ- +L---JF-JLJIIIIFJLJJ7 +|F|F-JF---7IIIL7L|7| +|FFJF7L7F-JF7IIL---7 +7-L-JL7||F7|L7F-7F7| +L.L7LFJ|||||FJL7||LJ +L7JLJL-JLJLJL--JLJ.L"; diff --git a/2023/src/direction.rs b/2023/src/direction.rs index 465cb20..f8a7199 100644 --- a/2023/src/direction.rs +++ b/2023/src/direction.rs @@ -1,11 +1,12 @@ use impl_ops::*; use std::{ - ops, + fmt, ops, ops::{AddAssign, Not}, }; pub const ALL_DIRECTIONS: [Direction; 4] = [Direction::Up, Direction::Down, Direction::Left, Direction::Right]; +#[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Direction { Right = 0, @@ -14,6 +15,21 @@ pub enum Direction { Up = 3, } +impl fmt::Display for Direction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Direction::Up => "Up", + Direction::Down => "Down", + Direction::Left => "Left", + Direction::Right => "Right", + } + ) + } +} + impl AddAssign for Direction { fn add_assign(&mut self, rhs: i8) { *self = *self + rhs; diff --git a/2023/src/position.rs b/2023/src/position.rs index 70d3089..0434418 100644 --- a/2023/src/position.rs +++ b/2023/src/position.rs @@ -3,7 +3,7 @@ use std::{ fmt::Debug, hash::Hash, iter::Step, - ops::{Add, AddAssign}, + ops::{Add, AddAssign, Index}, }; use crate::{common::Inc, direction::Direction}; @@ -55,6 +55,14 @@ where I: AddAssign + Copy } } +impl Index for PositionND { + type Output = I; + + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} + impl PositionND { pub fn neighbors_no_diagonals(&self) -> [PositionND; 4] { let PositionND([x, y]) = *self; diff --git a/2023/src/teststuff.rs b/2023/src/teststuff.rs index 2040fa9..6782724 100644 --- a/2023/src/teststuff.rs +++ b/2023/src/teststuff.rs @@ -8,8 +8,8 @@ macro_rules! boilerplate { $(unittests: { $($unittest: ident: { $($($utpi: expr),+ => $uto: expr),+$(,)? }),*$(,)? },)? - bench1$(($bi1: literal))? == $b1: literal, - bench2$(($bi2: literal))? == $b2: literal, + bench1$(($bi1: literal))? == $b1: expr, + bench2$(($bi2: literal))? == $b2: expr, bench_parse: $input_fn: expr => $it: expr$(,)? ) => { fn main() {