day6 part1

This commit is contained in:
Joe Ardent 2024-12-24 13:43:52 -08:00
parent 35ba924c1b
commit b79d418d4e
4 changed files with 253 additions and 1 deletions

7
Cargo.lock generated
View file

@ -31,6 +31,13 @@ dependencies = [
"winnow",
]
[[package]]
name = "day06"
version = "0.1.0"
dependencies = [
"winnow",
]
[[package]]
name = "memchr"
version = "2.7.4"

View file

@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["day01", "day02", "day03", "day04", "day05"]
members = ["day01", "day02", "day03", "day04", "day05", "day06"]
[workspace.dependencies]
winnow = "0.6"

7
day06/Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "day06"
version = "0.1.0"
edition = "2024"
[dependencies]
winnow.workspace = true

238
day06/src/main.rs Normal file
View file

@ -0,0 +1,238 @@
use std::{
collections::HashSet,
fmt::{Display, Write},
};
use winnow::{
PResult, Parser,
ascii::{newline, till_line_ending},
combinator::{alt, repeat, separated},
};
fn main() {
let input = std::fs::read_to_string("input").unwrap();
println!("{}", pt1(&input));
println!("{}", pt2(&input));
}
fn pt1(input: &str) -> usize {
let mut board = Board::new(input);
board.run()
}
fn pt2(input: &str) -> usize {
0
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
enum Dir {
#[default]
N,
S,
E,
W,
}
impl Dir {
fn next(&self, loc: Loc) -> Loc {
let Loc(r, c) = loc;
let (nr, nc) = match self {
Dir::N => (r.wrapping_sub(1), c),
Dir::S => (r + 1, c),
Dir::E => (r, c + 1),
Dir::W => (r, c.wrapping_sub(1)),
};
Loc(nr, nc)
}
fn rot(&self) -> Self {
use Dir::*;
match self {
N => E,
E => S,
S => W,
W => N,
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct Loc(usize, usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Cell {
Obstacle,
Empty,
Guard(Dir),
Visited,
}
impl Display for Cell {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Cell::*;
use Dir::*;
let c = match self {
Obstacle => '#',
Empty => '.',
Visited => 'X',
Guard(d) => match d {
N => '^',
E => '>',
S => 'v',
W => '<',
},
};
f.write_char(c)
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
struct Board {
cells: Vec<Vec<Cell>>,
guard: (Loc, Dir),
}
impl Display for Board {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(
&self
.cells
.iter()
//.map(|row| row.iter().map(|c| format!("{c}")).collect::<String>())
.map(|row| {
row.iter().fold(String::new(), |mut out, c| {
let _ = write!(out, "{c}");
out
})
})
.collect::<Vec<_>>()
.join("\n"),
)
}
}
impl Board {
fn new(input: &str) -> Self {
parse(input).unwrap()
}
fn step(&mut self) -> Option<Loc> {
let (loc, dir) = &mut self.guard;
*self
.cells
.get_mut(loc.0)
.and_then(|r| r.get_mut(loc.1))
.unwrap() = Cell::Visited;
let nloc = dir.next(*loc);
if let Some(next_cell) = self
.cells
.get_mut(nloc.0)
.and_then(|row| row.get_mut(nloc.1))
{
match next_cell {
Cell::Obstacle => {
*dir = dir.rot();
Some(*loc)
}
Cell::Empty | Cell::Visited => {
*next_cell = Cell::Guard(*dir);
*loc = nloc;
Some(nloc)
}
_ => unreachable!(),
}
} else {
None
}
}
fn run(&mut self) -> usize {
let mut locs = HashSet::new();
locs.insert(self.guard.0);
while let Some(loc) = self.step() {
locs.insert(loc);
}
locs.len()
}
}
fn parse_cell(input: &mut &str) -> PResult<Cell> {
alt((parse_guard, parse_floor)).parse_next(input)
}
fn parse_guard(input: &mut &str) -> PResult<Cell> {
let g = alt(('^', '>', 'v', '<')).parse_next(input)?;
use Cell::Guard;
use Dir::*;
match g {
'^' => Ok(Guard(N)),
'>' => Ok(Guard(E)),
'v' | 'V' => Ok(Guard(S)),
'<' => Ok(Guard(W)),
_ => unreachable!(),
}
}
fn parse_floor(input: &mut &str) -> PResult<Cell> {
let g = alt(('.', '#')).parse_next(input)?;
match g {
'.' => Ok(Cell::Empty),
'#' => Ok(Cell::Obstacle),
'X' => Ok(Cell::Visited),
_ => unreachable!(),
}
}
fn parse_line(input: &mut &str) -> PResult<Vec<Cell>> {
let mut line = till_line_ending.parse_next(input)?;
repeat(1.., parse_cell).parse_next(&mut line)
}
fn parse(input: &str) -> PResult<Board> {
let mut gdir = Dir::N;
let mut loc = Loc(0, 0);
let mut input = input;
let cells: Vec<Vec<Cell>> = separated(1.., parse_line, newline)
.parse_next(&mut input)
.unwrap();
for (row, line) in cells.iter().enumerate() {
for (col, cell) in line.iter().enumerate() {
if let Cell::Guard(d) = cell {
gdir = *d;
loc = Loc(row, col);
}
}
}
Ok(Board {
cells,
guard: (loc, gdir),
})
}
#[cfg(test)]
mod test {
use super::*;
static INPUT: &str = "....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...";
#[test]
fn p1() {
let v = pt1(INPUT);
assert_eq!(v, 41)
}
#[test]
fn p2() {}
}