#![allow(non_upper_case_globals)] use crate::prelude::*; pub type I = Vec>; 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) } }