Skip to content

Commit

Permalink
Day 23a
Browse files Browse the repository at this point in the history
  • Loading branch information
lpenz committed Dec 23, 2023
1 parent ecc16aa commit c4fd92b
Show file tree
Hide file tree
Showing 6 changed files with 331 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ members = [
"day20",
"day21",
"day22",
"day23",
]

10 changes: 10 additions & 0 deletions day23/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "day23"
version = "0.1.0"
edition = "2021"

[dependencies]
aoc = { path = "../aoc" }
color-eyre = "0.6.2"
nom = "7.1.3"
sqrid = "0.0.24"
141 changes: 141 additions & 0 deletions day23/input.txt

Large diffs are not rendered by default.

63 changes: 63 additions & 0 deletions day23/src/bin/day23a.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (C) 2023 Leandro Lisboa Penz <lpenz@lpenz.org>
// This file is subject to the terms and conditions defined in
// file 'LICENSE', which is part of this source code package.

use day23::*;

use std::collections::HashSet;

pub type Sqrid = sqrid::sqrid_create!(141, 141, false);
pub type Pos = sqrid::pos_create!(Sqrid);
pub type Grid = sqrid::grid_create!(Sqrid, Cell);

fn dfs(size: u16, grid: &Grid, pos: Pos, visited: &HashSet<Pos>, end: Pos, steps: usize) -> usize {
if pos == end {
return steps;
}
let pos_t = pos.tuple();
if pos_t.0 >= size || pos_t.1 >= size {
return 0;
}
if visited.contains(&pos) {
return 0;
}
if grid[pos] == Cell::Wall {
return 0;
}
let mut newvisited = visited.clone();
newvisited.insert(pos);
if let Cell::Slope(dir) = grid[pos] {
let Ok(newpos) = pos + dir else { return 0 };
dfs(size, grid, newpos, &newvisited, end, steps + 1)
} else {
Dir::iter::<false>()
.filter_map(|dir| {
(pos + dir)
.ok()
.map(|newpos| dfs(size, grid, newpos, &newvisited, end, steps + 1))
})
.max()
.unwrap_or(0)
}
}

fn process(size: u16, bufin: impl BufRead) -> Result<usize> {
let input = parser::parse(bufin)?;
let grid = Grid::try_from(input)?;
let start = Pos::try_from((1, 0))?;
assert_eq!(grid[start], Cell::Empty);
let end = Pos::try_from((size - 2, size - 1))?;
assert_eq!(grid[end], Cell::Empty);
let visited = Default::default();
Ok(dfs(size, &grid, start, &visited, end, 0))
}

#[test]
fn test() -> Result<()> {
assert_eq!(process(23, EXAMPLE.as_bytes())?, 94);
Ok(())
}

fn main() -> Result<()> {
do_main(|| process(141, stdin().lock()))
}
106 changes: 106 additions & 0 deletions day23/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (C) 2023 Leandro Lisboa Penz <lpenz@lpenz.org>
// This file is subject to the terms and conditions defined in
// file 'LICENSE', which is part of this source code package.

pub use aoc::*;

use std::fmt;

pub const EXAMPLE: &str = "#.#####################
#.......#########...###
#######.#########.#.###
###.....#.>.>.###.#.###
###v#####.#v#.###.#.###
###.>...#.#.#.....#...#
###v###.#.#.#########.#
###...#.#.#.......#...#
#####.#.#.#######.#.###
#.....#.#.#.......#...#
#.#####.#.#.#########v#
#.#...#...#...###...>.#
#.#.#v#######v###.###v#
#...#.>.#...>.>.#.###.#
#####v#.#.###v#.#.###.#
#.....#...#...#.#.#...#
#.#########.###.#.#.###
#...###...#...#...#.###
###.###.#.###v#####v###
#...#...#.#.>.>.#.>.###
#.###.###.#.###.#.#v###
#.....###...###...#...#
#####################.#
";

pub use sqrid::Dir;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Cell {
#[default]
Empty,
Wall,
Slope(Dir),
}

impl TryFrom<char> for Cell {
type Error = Report;
fn try_from(c: char) -> Result<Self, Self::Error> {
match c {
'.' => Ok(Cell::Empty),
'#' => Ok(Cell::Wall),
'^' => Ok(Cell::Slope(Dir::N)),
'>' => Ok(Cell::Slope(Dir::E)),
'v' => Ok(Cell::Slope(Dir::S)),
'<' => Ok(Cell::Slope(Dir::W)),
other => Err(eyre!("invalid cell {}", other)),
}
}
}

impl From<&Cell> for char {
fn from(c: &Cell) -> Self {
match c {
Cell::Empty => '.',
Cell::Wall => '#',
Cell::Slope(Dir::N) => '^',
Cell::Slope(Dir::E) => '>',
Cell::Slope(Dir::S) => 'v',
Cell::Slope(Dir::W) => '<',
_ => unreachable!(),
}
}
}

impl fmt::Display for Cell {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", char::from(self))
}
}

pub mod parser {
use aoc::parser::*;

use super::*;

fn cell(input: &str) -> IResult<&str, Cell> {
let (input, c) = character::one_of(".#^>v<")(input)?;
Ok((input, Cell::try_from(c).unwrap()))
}

fn line(input: &str) -> IResult<&str, Vec<Cell>> {
let (input, cells) = multi::many1(cell)(input)?;
let (input, _) = character::newline(input)?;
Ok((input, cells))
}

pub fn parse(mut bufin: impl BufRead) -> Result<Vec<Vec<Cell>>> {
aoc::parse_with!(multi::many1(line), bufin)
}
}

#[test]
fn test() -> Result<()> {
let input = parser::parse(EXAMPLE.as_bytes())?;
assert_eq!(input.len(), 23);
assert_eq!(input[0].len(), 23);
Ok(())
}

0 comments on commit c4fd92b

Please sign in to comment.