Skip to content

Commit

Permalink
Fail to solve 2023 day 10 part 2
Browse files Browse the repository at this point in the history
jeffs committed Dec 11, 2023
1 parent ca5761a commit 2a707fd
Showing 4 changed files with 129 additions and 61 deletions.
10 changes: 10 additions & 0 deletions 2023/day10/src/direction.rs
Original file line number Diff line number Diff line change
@@ -8,6 +8,16 @@ pub enum Direction {
}

impl Direction {
pub fn iter() -> impl Iterator<Item = Direction> {
[
Direction::North,
Direction::East,
Direction::South,
Direction::West,
]
.into_iter()
}

pub fn reverse(self) -> Direction {
match self {
Direction::North => Direction::South,
51 changes: 35 additions & 16 deletions 2023/day10/src/grid.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(dead_code)]

use crate::{direction::Direction, position::Position, tile::Tile};

pub struct Grid(Vec<Vec<Tile>>);
@@ -28,27 +30,44 @@ impl Grid {

pub fn exits(&self, from: Position) -> impl Iterator<Item = Position> + '_ {
let tile = self.at(from).expect("valid from position");
[
Direction::North,
Direction::East,
Direction::South,
Direction::West,
]
.into_iter()
.filter(move |&dir| tile.is_open_to(dir))
.flat_map(move |dir| {
from.go(dir).filter(|&pos| {
self.at(pos)
.is_some_and(|tile| tile.is_open_to(dir.reverse()))
Direction::iter()
.filter(move |&dir| tile.is_open_to(dir))
.flat_map(move |dir| {
from.go(dir).filter(|&pos| {
self.at(pos)
.is_some_and(|tile| tile.is_open_to(dir.reverse()))
})
})
}

pub fn is_ground(&self, pos: Position) -> bool {
self.at(pos).is_some_and(Tile::is_ground)
}

pub fn enumerate(&self) -> impl Iterator<Item = (Position, Tile)> + '_ {
self.0.iter().enumerate().flat_map(|(i, row)| {
row.iter()
.enumerate()
.map(move |(j, tile)| (Position(i, j), *tile))
})
}

pub fn ground_len(&self) -> usize {
pub fn iter(&self) -> impl Iterator<Item = Tile> + '_ {
self.0.iter().flat_map(|row| row.iter()).cloned()
}

pub fn height(&self) -> usize {
self.0.len()
}

pub fn width(&self) -> usize {
self.0.get(0).map(|row| row.len()).unwrap_or_default()
}

pub fn to_ascii(&self) -> Vec<Vec<u8>> {
self.0
.iter()
.flatten()
.filter(|&&tile| tile == Tile::Ground)
.count()
.map(|row| row.iter().map(|tile| tile.to_ascii()).collect())
.collect()
}
}
41 changes: 32 additions & 9 deletions 2023/day10/src/part2.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashSet;

use crate::{grid::Grid, position::Position, tile::Tile};
use crate::{direction::Direction, grid::Grid};

pub fn solve(text: &str) -> usize {
let grid = Grid::from_str(text);
@@ -16,22 +16,45 @@ pub fn solve(text: &str) -> usize {
.exits(start)
.next()
.expect("somewhere reachable from the start position");
let mut outside = HashSet::<Position>::new();
let mut outside = Vec::new();
while new != start {
let pos = grid
.exits(new)
.find(|&pos| pos != old)
.expect("somewhere reachable from each reachable position");
let dir = new.dir(pos);
if let Some(left) = pos.go(dir.left()) {
if let Some(Tile::Ground) = grid.at(left) {
// dbg!(left);
outside.insert(left);
}
if let Some(left) = pos
.go(new.dir(pos).left())
.filter(|&left| grid.is_ground(left))
{
outside.push(left);
}
(old, new) = (new, pos);
}
grid.ground_len() - outside.len()

let mut seen = HashSet::new();
while let Some(pos) = outside.pop() {
seen.insert(pos);
outside.extend(
Direction::iter()
.flat_map(|dir| pos.go(dir))
.filter(|&next| grid.is_ground(next))
.filter(|&next| seen.insert(next)),
);
}

let mut ascii = grid.to_ascii();
for &pos in seen.iter() {
ascii[pos.0][pos.1] = b'O';
}

let lines: Vec<String> = ascii
.into_iter()
.map(|row| String::from_utf8_lossy(&row).into_owned())
.collect();
eprintln!("\n{}\n", lines.join("\n"));

let ground_len = grid.iter().filter(|tile| tile.is_ground()).count();
ground_len - seen.len()
}

#[cfg(test)]
88 changes: 52 additions & 36 deletions 2023/day10/src/tile.rs
Original file line number Diff line number Diff line change
@@ -3,30 +3,46 @@ use crate::direction::Direction;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum Tile {
Vertical,
Horizontal,
NorthEast,
NorthWest,
SouthWest,
SouthEast,
VerticalPipe,
HorizontalPipe,
NorthEastBend,
NorthWestBend,
SouthWestBend,
SouthEastBend,
Ground,
Start,
}

impl Tile {
pub fn from_ascii(c: u8) -> Tile {
match c {
b'|' => Tile::Vertical,
b'-' => Tile::Horizontal,
b'L' => Tile::NorthEast,
b'J' => Tile::NorthWest,
b'7' => Tile::SouthWest,
b'F' => Tile::SouthEast,
b'|' => Tile::VerticalPipe,
b'-' => Tile::HorizontalPipe,
b'L' => Tile::NorthEastBend,
b'J' => Tile::NorthWestBend,
b'7' => Tile::SouthWestBend,
b'F' => Tile::SouthEastBend,
b'.' => Tile::Ground,
b'S' => Tile::Start,
_ => panic!("{}: bad tile", c as char),
}
}
pub fn to_ascii(self) -> u8 {
match self {
Tile::VerticalPipe => b'|',
Tile::HorizontalPipe => b'-',
Tile::NorthEastBend => b'L',
Tile::NorthWestBend => b'J',
Tile::SouthWestBend => b'7',
Tile::SouthEastBend => b'F',
Tile::Ground => b'.',
Tile::Start => b'S',
}
}

pub fn is_ground(self) -> bool {
self == Tile::Ground
}

pub fn is_open_to(self, dir: Direction) -> bool {
0xF06C93A5u32 & 1 << (self as u32 * 4 + dir as u32) != 0
@@ -39,35 +55,35 @@ mod tests {

#[test]
fn tile_is_open_to() {
assert!(Tile::Vertical.is_open_to(Direction::North));
assert!(!Tile::Vertical.is_open_to(Direction::East));
assert!(Tile::Vertical.is_open_to(Direction::South));
assert!(!Tile::Vertical.is_open_to(Direction::West));
assert!(Tile::VerticalPipe.is_open_to(Direction::North));
assert!(!Tile::VerticalPipe.is_open_to(Direction::East));
assert!(Tile::VerticalPipe.is_open_to(Direction::South));
assert!(!Tile::VerticalPipe.is_open_to(Direction::West));

assert!(!Tile::Horizontal.is_open_to(Direction::North));
assert!(Tile::Horizontal.is_open_to(Direction::East));
assert!(!Tile::Horizontal.is_open_to(Direction::South));
assert!(Tile::Horizontal.is_open_to(Direction::West));
assert!(!Tile::HorizontalPipe.is_open_to(Direction::North));
assert!(Tile::HorizontalPipe.is_open_to(Direction::East));
assert!(!Tile::HorizontalPipe.is_open_to(Direction::South));
assert!(Tile::HorizontalPipe.is_open_to(Direction::West));

assert!(Tile::NorthEast.is_open_to(Direction::North));
assert!(Tile::NorthEast.is_open_to(Direction::East));
assert!(!Tile::NorthEast.is_open_to(Direction::South));
assert!(!Tile::NorthEast.is_open_to(Direction::West));
assert!(Tile::NorthEastBend.is_open_to(Direction::North));
assert!(Tile::NorthEastBend.is_open_to(Direction::East));
assert!(!Tile::NorthEastBend.is_open_to(Direction::South));
assert!(!Tile::NorthEastBend.is_open_to(Direction::West));

assert!(Tile::NorthWest.is_open_to(Direction::North));
assert!(!Tile::NorthWest.is_open_to(Direction::East));
assert!(!Tile::NorthWest.is_open_to(Direction::South));
assert!(Tile::NorthWest.is_open_to(Direction::West));
assert!(Tile::NorthWestBend.is_open_to(Direction::North));
assert!(!Tile::NorthWestBend.is_open_to(Direction::East));
assert!(!Tile::NorthWestBend.is_open_to(Direction::South));
assert!(Tile::NorthWestBend.is_open_to(Direction::West));

assert!(!Tile::SouthWest.is_open_to(Direction::North));
assert!(!Tile::SouthWest.is_open_to(Direction::East));
assert!(Tile::SouthWest.is_open_to(Direction::South));
assert!(Tile::SouthWest.is_open_to(Direction::West));
assert!(!Tile::SouthWestBend.is_open_to(Direction::North));
assert!(!Tile::SouthWestBend.is_open_to(Direction::East));
assert!(Tile::SouthWestBend.is_open_to(Direction::South));
assert!(Tile::SouthWestBend.is_open_to(Direction::West));

assert!(!Tile::SouthEast.is_open_to(Direction::North));
assert!(Tile::SouthEast.is_open_to(Direction::East));
assert!(Tile::SouthEast.is_open_to(Direction::South));
assert!(!Tile::SouthEast.is_open_to(Direction::West));
assert!(!Tile::SouthEastBend.is_open_to(Direction::North));
assert!(Tile::SouthEastBend.is_open_to(Direction::East));
assert!(Tile::SouthEastBend.is_open_to(Direction::South));
assert!(!Tile::SouthEastBend.is_open_to(Direction::West));

assert!(!Tile::Ground.is_open_to(Direction::North));
assert!(!Tile::Ground.is_open_to(Direction::East));

0 comments on commit 2a707fd

Please sign in to comment.