diff --git a/d22/part1.rs b/d22/part1.rs new file mode 100644 index 0000000..8a4535e --- /dev/null +++ b/d22/part1.rs @@ -0,0 +1,146 @@ +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); +} diff --git a/d22/part2.rs b/d22/part2.rs new file mode 100644 index 0000000..745f364 --- /dev/null +++ b/d22/part2.rs @@ -0,0 +1,197 @@ +use std::iter::repeat; + +type Pos = (isize, isize); + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +struct Instruction { + dist: Option, + rotation: Option, +} + +fn rotate(facing: Pos, by: isize) -> Pos { + match by.rem_euclid(4) { + 0 => facing, + 1 => (-facing.1, facing.0), + 2 => (-facing.0, -facing.1), + 3 => (facing.1, -facing.0), + _ => unreachable!(), + } +} + +fn facing_angle_to_axes(facing: isize) -> Pos { + match facing.rem_euclid(4) { + 0 => (1, 0), + 1 => (0, 1), + 2 => (-1, 0), + 3 => (0, -1), + _ => unreachable!(), + } +} + +fn next_pos_facing( + pos: Pos, + facing: Pos, + map: &Vec>, + edges: &Vec<(Vec, Vec, isize, isize)>, +) -> (Pos, Pos) { + let mut next_pos = (pos.0 + facing.0, pos.1 + facing.1); + let mut next_facing = facing; + for edge in edges.iter() { + if let Some(i) = edge.0.iter().position(|p| *p == pos) { + if facing_angle_to_axes(edge.2) == facing { + (next_pos, next_facing) = (edge.1[i], rotate(facing, (edge.3 + 2) - edge.2)); + #[cfg(debug_assertions)] + println!( + "cross edge: {} {} ({} {}) -> {} {} ({} {})", + pos.0, + pos.1, + facing.0, + facing.1, + next_pos.0, + next_pos.1, + next_facing.0, + next_facing.1 + ); + } + } else if let Some(i) = edge.1.iter().position(|p| *p == pos) { + if facing_angle_to_axes(edge.3) == facing { + (next_pos, next_facing) = (edge.0[i], rotate(facing, (edge.2 + 2) - edge.3)); + #[cfg(debug_assertions)] + println!( + "cross edge: {} {} ({} {}) -> {} {} ({} {})", + pos.0, + pos.1, + facing.0, + facing.1, + next_pos.0, + next_pos.1, + next_facing.0, + next_facing.1 + ); + } + } + } + (next_pos, next_facing) +} + +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 l = 50isize; + #[rustfmt::skip] + let edges: Vec<(Vec, Vec, isize, isize)> = vec![ + ((0..l).zip(repeat(l*2).take(l as usize)).collect(), repeat(l).take(l as usize).zip(l..l*2).collect(), 3, 2), + (repeat(0).take(l as usize).zip(l*2..l*3).collect(), repeat(l).take(l as usize).zip((0..l).rev()).collect(), 2, 2), + (repeat(0).take(l as usize).zip(l*3..l*4).collect(), (l..l*2).zip(repeat(0).take(l as usize)).collect(), 2, 3), + ((0..l).zip(repeat(l*4-1).take(l as usize)).collect(), (l*2..l*3).zip(repeat(0).take(l as usize)).collect(), 1, 3), + (repeat(l-1).take(l as usize).zip(l*3..l*4).collect(), (l..l*2).zip(repeat(l*3-1).take(l as usize)).collect(), 0, 1), + (repeat(l*2-1).take(l as usize).zip(l*2..l*3).collect(), repeat(l*3-1).take(l as usize).zip((0..l).rev()).collect(), 0, 0), + (repeat(l*2-1).take(l as usize).zip(l..l*2).collect(), (l*2..l*3).zip(repeat(l-1).take(l as usize)).collect(), 0, 1), + ]; + 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 (next_pos, next_facing) = next_pos_facing(pos, facing, &map, &edges); + match map[next_pos.1 as usize][next_pos.0 as usize] { + b'#' => { + break; + } + b'.' => { + (pos, facing) = (next_pos, next_facing); + } + _ => { + panic!("unexpected wall as next character"); + } + } + } + } + (None, Some(rot)) => { + (facing.0, facing.1) = rotate((facing.0, facing.1), rot); + } + _ => 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() * (2 - 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); +}