diff options
Diffstat (limited to '2023/src/bin')
-rw-r--r-- | 2023/src/bin/day_10.rs | 224 |
1 files changed, 216 insertions, 8 deletions
diff --git a/2023/src/bin/day_10.rs b/2023/src/bin/day_10.rs index b3a610b..e351c34 100644 --- a/2023/src/bin/day_10.rs +++ b/2023/src/bin/day_10.rs @@ -1,19 +1,227 @@ -use nom::IResult; +use nom::{ + branch::alt, + character::complete::{char as nom_char, line_ending}, + combinator::{map, value}, + multi::{many1, separated_list1}, + IResult, +}; use std::fs; fn main() -> Result<(), Box<dyn std::error::Error>> { - let input = fs::read_to_string("inputs/day_2.txt")?; - let parsed = Example::parser(&input).unwrap().1; - dbg!(&parsed); + let input = fs::read_to_string("inputs/day_10.txt")?; + let parsed = Maze::parser(&input).unwrap().1; + dbg!(&parsed.find_furthest_point_in_loop()); Ok(()) } #[derive(Debug)] -struct Example; +struct Maze(Vec<Vec<Pipe>>); -impl Example { - fn parser(_input: &str) -> IResult<&str, Self> { - todo!() +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Pipe { + Start, + Nothing, + DownLeft, + DownRight, + DownUp, + LeftRight, + UpLeft, + UpRight, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Direction { + Up, + Down, + Left, + Right, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct Point { + x: usize, + y: usize, +} + +impl Maze { + fn parser(input: &str) -> IResult<&str, Self> { + map(separated_list1(line_ending, many1(Pipe::parser)), Maze)(input) + } + + fn find_furthest_point_in_loop(&self) -> usize { + self.measure_loop_size() / 2 + } + + fn measure_loop_size(&self) -> usize { + let mut position = self.find_start(); + let mut facing = if position.y > 0 + && self + .at(position.up()) + .connections() + .contains(&Direction::Down) + { + position = position.up(); + Direction::Up + } else if position.y < self.0.len() - 1 + && self + .at(position.down()) + .connections() + .contains(&Direction::Up) + { + position = position.down(); + Direction::Down + } else if position.x > 0 + && self + .at(position.left()) + .connections() + .contains(&Direction::Right) + { + position = position.left(); + Direction::Left + } else if position.x < self.0[position.y].len() - 1 + && self + .at(position.right()) + .connections() + .contains(&Direction::Left) + { + position = position.right(); + Direction::Right + } else { + panic!() + }; + let mut distance = 1; + + while self.at(position) != Pipe::Start { + let current_pipe = self.at(position); + facing = current_pipe.exit_facing(facing).unwrap(); + position = match facing { + Direction::Up => position.up(), + Direction::Down => position.down(), + Direction::Left => position.left(), + Direction::Right => position.right(), + }; + distance += 1; + } + + distance + } + + fn at(&self, p: Point) -> Pipe { + self.0[p.y][p.x] + } + + fn find_start(&self) -> Point { + for (y, row) in self.0.iter().enumerate() { + for (x, pipe) in row.iter().enumerate() { + if *pipe == Pipe::Start { + return Point { x, y }; + } + } + } + panic!("No Start!"); + } +} + +impl Pipe { + fn parser(input: &str) -> IResult<&str, Self> { + use Pipe::*; + + alt(( + value(Start, nom_char('S')), + value(Nothing, nom_char('.')), + value(DownLeft, nom_char('7')), + value(DownRight, nom_char('F')), + value(DownUp, nom_char('|')), + value(LeftRight, nom_char('-')), + value(UpLeft, nom_char('J')), + value(UpRight, nom_char('L')), + ))(input) + } + + fn connections(&self) -> Vec<Direction> { + use Direction::*; + + match self { + Pipe::Start => vec![], + Pipe::Nothing => vec![], + Pipe::DownLeft => vec![Down, Left], + Pipe::DownRight => vec![Down, Right], + Pipe::DownUp => vec![Down, Up], + Pipe::LeftRight => vec![Left, Right], + Pipe::UpLeft => vec![Up, Left], + Pipe::UpRight => vec![Up, Right], + } + } + + fn exit_facing(&self, facing: Direction) -> Option<Direction> { + use Direction::*; + + match self { + Pipe::Start => None, + Pipe::Nothing => None, + Pipe::DownLeft => match facing { + Up => Some(Left), + Right => Some(Down), + _ => None, + }, + Pipe::DownRight => match facing { + Up => Some(Right), + Left => Some(Down), + _ => None, + }, + Pipe::DownUp => match facing { + Up => Some(Up), + Down => Some(Down), + _ => None, + }, + Pipe::LeftRight => match facing { + Left => Some(Left), + Right => Some(Right), + _ => None, + }, + Pipe::UpLeft => match facing { + Down => Some(Left), + Right => Some(Up), + _ => None, + }, + Pipe::UpRight => match facing { + Down => Some(Right), + Left => Some(Up), + _ => None, + }, + } + } +} + +impl Point { + fn up(&self) -> Point { + Point { + x: self.x, + y: self.y - 1, + } + } + + fn down(&self) -> Point { + Point { + x: self.x, + y: self.y + 1, + } + } + + fn left(&self) -> Point { + Point { + x: self.x - 1, + y: self.y, + } + } + + fn right(&self) -> Point { + Point { + x: self.x + 1, + y: self.y, + } } } + +// 6756 is too low |