use std::iter::repeat; #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub struct Instruction { dist: Option, rotation: Option, } pub fn main() { let s = include_bytes!("./input"); let mut pos = (s.iter().position(|b| *b == b'.').unwrap() as isize, 0); let mut facing: (isize, isize) = (1, 0); let w = s .split(|b| *b == b'\n') .take_while(|l| !l.is_empty()) .map(|l| l.len()) .max() .unwrap(); let map = s .split(|b| *b == b'\n') .take_while(|l| !l.is_empty()) .map(|l| { l.iter() .take(l.len()) .chain(repeat(&b' ').take(w - l.len())) .copied() .collect::>() }) .collect::>(); let h = map.len(); let mut path: Vec = Vec::new(); let mut acc = 0; s.split(|b| *b == b'\n') .rev() .nth(1) .unwrap() .iter() .for_each(|b| match b { b'0'..=b'9' => { acc = acc * 10 + (b - b'0') as isize; } b'R' => { path.push(Instruction { dist: Some(acc), rotation: None, }); path.push(Instruction { dist: None, rotation: Some(1), }); acc = 0; } b'L' => { path.push(Instruction { dist: Some(acc), rotation: None, }); path.push(Instruction { dist: None, rotation: Some(-1), }); acc = 0; } _ => unreachable!(), }); path.push(Instruction { dist: Some(acc), rotation: None, }); #[cfg(debug_assertions)] println!("{} {}", map.len(), map[0].len()); #[cfg(debug_assertions)] println!( "pos: ({}, {}), facing ({} {})", pos.0, pos.1, facing.0, facing.1 ); for ins in path.iter() { #[cfg(debug_assertions)] println!("{:?}", ins); match (ins.dist, ins.rotation) { (Some(dist), None) => { for step in 0..dist { let mut next_pos = (pos.0 + facing.0, pos.1 + facing.1); #[cfg(debug_assertions)] println!("next_pos: {} {}", next_pos.0, next_pos.1); let next_char = if next_pos.0 >= 0 && next_pos.0 < w as isize && next_pos.1 >= 0 && next_pos.1 < h as isize { Some(map[next_pos.1 as usize][next_pos.0 as usize]) } else { None }; if next_char == Some(b'.') { pos = next_pos; } else if next_char.is_none() || next_char == Some(b' ') { next_pos = (pos.0 - facing.0, pos.1 - facing.1); while next_pos.0 >= 0 && next_pos.0 < w as isize && next_pos.1 >= 0 && next_pos.1 < h as isize && map[next_pos.1 as usize][next_pos.0 as usize] != b' ' { next_pos = (next_pos.0 - facing.0, next_pos.1 - facing.1); } next_pos = (next_pos.0 + facing.0, next_pos.1 + facing.1); if map[next_pos.1 as usize][next_pos.0 as usize] != b'#' { pos = next_pos; } else { #[cfg(debug_assertions)] println!("pos: {} {}", pos.0, pos.1); break; } } else { #[cfg(debug_assertions)] println!("pos: {} {}", pos.0, pos.1); break; } } } (None, Some(rot)) => match rot { 1 => (facing.0, facing.1) = (-facing.1, facing.0), -1 => (facing.0, facing.1) = (facing.1, -facing.0), _ => unreachable!(), }, _ => unreachable!(), } #[cfg(debug_assertions)] println!( "pos: ({}, {}), facing ({} {})", pos.0, pos.1, facing.0, facing.1 ); } let facing_dir = facing.0.abs() * (1 - facing.0) + facing.1.abs() * (1 - facing.1); #[cfg(debug_assertions)] println!( "pos: ({}, {}), facing ({} {}) = {}", pos.0 + 1, pos.1 + 1, facing.0, facing.1, facing_dir ); print!("{} ", 1000 * (pos.1 + 1) + 4 * (pos.0 + 1) + facing_dir); }