132 lines
3.0 KiB
Rust
132 lines
3.0 KiB
Rust
|
|
#![allow(non_upper_case_globals)]
|
||
|
|
use crate::prelude::*;
|
||
|
|
|
||
|
|
pub type I = Vec<Vec<char>>;
|
||
|
|
pub type O = usize;
|
||
|
|
|
||
|
|
fn _parse (data: &str) -> I {
|
||
|
|
data.lines().map(|line| line.chars().collect()).collect()
|
||
|
|
}
|
||
|
|
|
||
|
|
fn _traverse (data: &I) -> S<(usize, usize)> {
|
||
|
|
let (mut sy, mut sx) = data.iter().enumerate().find_map(|(y, row)| row.iter().position(|e| *e == '^').map(|x| (y, x))).unwrap();
|
||
|
|
|
||
|
|
let rows = data.len();
|
||
|
|
let cols = data[0].len();
|
||
|
|
|
||
|
|
let mut s: S<(usize, usize)> = S::new();
|
||
|
|
const dirs: [(isize, isize); 4] = [(-1, 0), (0, 1), (1, 0), (0, -1)];
|
||
|
|
let mut dir = 0;
|
||
|
|
|
||
|
|
loop {
|
||
|
|
|
||
|
|
let (dy, dx) = dirs[dir];
|
||
|
|
let ny = sy.checked_add_signed(dy);
|
||
|
|
let nx = sx.checked_add_signed(dx);
|
||
|
|
|
||
|
|
match (ny, nx) {
|
||
|
|
(Some(ny), Some(nx)) if ny < rows && nx < cols => {
|
||
|
|
if data[ny][nx] == '#' {
|
||
|
|
dir = (dir + 1) % 4;
|
||
|
|
} else {
|
||
|
|
s.insert((ny, nx));
|
||
|
|
sy = ny;
|
||
|
|
sx = nx;
|
||
|
|
}
|
||
|
|
},
|
||
|
|
_ => break,
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
s
|
||
|
|
}
|
||
|
|
|
||
|
|
fn _silver (data: I) -> O {
|
||
|
|
let ans = _traverse(&data);
|
||
|
|
ans.len()
|
||
|
|
}
|
||
|
|
|
||
|
|
fn _gold (mut data: I) -> O {
|
||
|
|
let path = _traverse(&data);
|
||
|
|
let (sy, sx) = data.iter().enumerate().find_map(|(y, row)| row.iter().position(|e| *e == '^').map(|x| (y, x))).unwrap();
|
||
|
|
data[sy][sx] = '.';
|
||
|
|
|
||
|
|
let rows = data.len();
|
||
|
|
let cols = data[0].len();
|
||
|
|
|
||
|
|
const dirs: [(isize, isize); 4] = [(-1, 0), (0, 1), (1, 0), (0, -1)];
|
||
|
|
|
||
|
|
let mut loops = 0;
|
||
|
|
|
||
|
|
'outer : for (cy, cx) in path {
|
||
|
|
if cy == sy && cx == sx { continue; }
|
||
|
|
if data[cy][cx] == '.' {
|
||
|
|
data[cy][cx] = '#';
|
||
|
|
|
||
|
|
let mut y = sy;
|
||
|
|
let mut x = sx;
|
||
|
|
|
||
|
|
let mut s: S<((usize, usize), usize)> = S::new();
|
||
|
|
let mut dir = 0;
|
||
|
|
|
||
|
|
'inner : loop {
|
||
|
|
let (dy, dx) = dirs[dir];
|
||
|
|
|
||
|
|
if s.contains(&((y, x), dir)) {
|
||
|
|
loops += 1;
|
||
|
|
data[cy][cx] = '.';
|
||
|
|
continue 'outer;
|
||
|
|
}
|
||
|
|
s.insert(((y, x), dir));
|
||
|
|
|
||
|
|
let ny = y.checked_add_signed(dy);
|
||
|
|
let nx = x.checked_add_signed(dx);
|
||
|
|
|
||
|
|
match (ny, nx) {
|
||
|
|
(Some(ny), Some(nx)) if ny < rows && nx < cols => {
|
||
|
|
if data[ny][nx] == '#' {
|
||
|
|
dir = (dir + 1) % 4;
|
||
|
|
} else {
|
||
|
|
y = ny;
|
||
|
|
x = nx;
|
||
|
|
}
|
||
|
|
},
|
||
|
|
_ => break 'inner,
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
data[cy][cx] = '.';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
loops
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(test)]
|
||
|
|
mod test {
|
||
|
|
use super::*;
|
||
|
|
|
||
|
|
fn read () -> I {
|
||
|
|
let data = inc!(6);
|
||
|
|
_parse(data)
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn silver () {
|
||
|
|
let data = read();
|
||
|
|
let ans = _silver(data);
|
||
|
|
|
||
|
|
assert_eq!(ans, 4967)
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn gold () {
|
||
|
|
let data = read();
|
||
|
|
let ans = _gold(data);
|
||
|
|
|
||
|
|
assert_eq!(ans, 1789)
|
||
|
|
}
|
||
|
|
}
|