From 5e6870d092106d2211a6878d50e992ac28482a9e Mon Sep 17 00:00:00 2001 From: jazzpi Date: Thu, 22 Dec 2022 12:57:38 +0100 Subject: [PATCH] Day 22, part 1 --- src/bin/d22p1.rs | 18 +++++ src/day22.rs | 188 +++++++++++++++++++++++++++++++++++++++++++++++ src/day9.rs | 8 +- src/lib.rs | 1 + src/util.rs | 31 ++++++++ 5 files changed, 239 insertions(+), 7 deletions(-) create mode 100644 src/bin/d22p1.rs create mode 100644 src/day22.rs diff --git a/src/bin/d22p1.rs b/src/bin/d22p1.rs new file mode 100644 index 0000000..8075842 --- /dev/null +++ b/src/bin/d22p1.rs @@ -0,0 +1,18 @@ +use aoc22::{day22, util}; + +pub fn main() { + let (grid, instructions) = day22::parse_map_and_path(&util::parse_input()); + + // dbg!(&grid); + // dbg!(&instructions); + + let mut pose = day22::Pose::new(&grid); + // dbg!(&pose); + for inst in &instructions { + pose = day22::exec_instruction(&grid, &pose, inst); + // dbg!(&pose); + } + + let pass = 1000 * (pose.pos.0 + 1) + 4 * (pose.pos.1 + 1) + (pose.orientation as usize); + println!("Passowrd: {}", pass); +} diff --git a/src/day22.rs b/src/day22.rs new file mode 100644 index 0000000..653e1c2 --- /dev/null +++ b/src/day22.rs @@ -0,0 +1,188 @@ +use itertools::Itertools; + +use crate::util::Dir; + +#[derive(Debug)] +pub enum TurnDir { + CW, + CCW, +} + +#[derive(Debug)] +pub enum Instruction { + Move(isize), + Turn(TurnDir), +} + +#[derive(Debug)] +pub struct Grid { + pub grid: Vec>>, + pub height: usize, + pub width: usize, + pub row_bounds: Vec<(usize, usize)>, + pub col_bounds: Vec<(usize, usize)>, +} + +pub fn parse_map_and_path(input: &str) -> (Grid, Vec) { + let lines = input.lines().collect_vec(); + + let mut grid: Vec>> = Vec::new(); + let mut width = 0; + for line in &lines[..lines.len() - 2] { + width = width.max(line.len()); + let grid_line = line + .chars() + .map(|c| match c { + ' ' => None, + '.' => Some(false), + '#' => Some(true), + _ => panic!("Unknown grid character {}", c), + }) + .collect(); + grid.push(grid_line); + } + + let height = grid.len(); + let mut row_bounds = vec![(0, 0); height]; + for row in 0..height { + let row_width = grid[row].len(); + if row_width < width { + grid[row].extend((row_width..width).map(|_| None)); + } + let lower = grid[row].iter().position(Option::is_some).unwrap(); + let upper = width - 1 - grid[row].iter().rev().position(Option::is_some).unwrap(); + row_bounds[row] = (lower, upper); + } + + let mut col_bounds = vec![(0, 0); width]; + for col in 0..width { + let col_it = (0..height).map(|row| grid[row][col]); + let lower = col_it.clone().position(|t| t.is_some()).unwrap(); + let upper = height - 1 - col_it.rev().position(|t| t.is_some()).unwrap(); + col_bounds[col] = (lower, upper); + } + + let grid = Grid { + grid, + height, + width, + row_bounds, + col_bounds, + }; + + let mut instructions = Vec::new(); + let mut inst_begin = 0; + let inst_line = lines[lines.len() - 1].as_bytes(); + while inst_begin < inst_line.len() { + let mut i = inst_begin; + let c = inst_line[i]; + if c.is_ascii_digit() { + while i < inst_line.len() && inst_line[i].is_ascii_digit() { + i += 1; + } + let dist = std::str::from_utf8(&inst_line[inst_begin..i]) + .unwrap() + .parse() + .unwrap(); + instructions.push(Instruction::Move(dist)); + inst_begin = i; + continue; + } + + let dir = match c { + b'L' => TurnDir::CCW, + b'R' => TurnDir::CW, + _ => panic!("Unknown turn direction {}", c), + }; + instructions.push(Instruction::Turn(dir)); + inst_begin += 1; + } + + (grid, instructions) +} + +#[derive(Debug)] +pub struct Pose { + pub pos: (usize, usize), + pub orientation: Dir, +} + +impl Pose { + pub fn new(grid: &Grid) -> Pose { + let col = grid.grid[0] + .iter() + .position(|t| if let Some(occ) = t { !occ } else { false }) + .unwrap(); + Pose { + pos: (0, col), + orientation: Dir::Right, + } + } +} + +pub fn exec_instruction(grid: &Grid, pose: &Pose, instr: &Instruction) -> Pose { + match instr { + Instruction::Turn(turn_dir) => Pose { + pos: pose.pos, + orientation: match turn_dir { + TurnDir::CW => pose.orientation.cw(), + TurnDir::CCW => pose.orientation.ccw(), + }, + }, + Instruction::Move(n) => { + let mut pos = pose.pos; + + for _ in 0..*n { + let next_pos = match pose.orientation { + Dir::Left => { + let bounds = &grid.row_bounds[pos.0]; + let next_col = if pos.1 == 0 || pos.1 == bounds.0 { + bounds.1 + } else { + pos.1 - 1 + }; + (pos.0, next_col) + } + Dir::Up => { + let bounds = &grid.col_bounds[pos.1]; + let next_row = if pos.0 == 0 || pos.0 == bounds.0 { + bounds.1 + } else { + pos.0 - 1 + }; + (next_row, pos.1) + } + Dir::Right => { + let bounds = &grid.row_bounds[pos.0]; + let next_col = if pos.1 == bounds.1 { + bounds.0 + } else { + pos.1 + 1 + }; + (pos.0, next_col) + } + Dir::Down => { + let bounds = &grid.col_bounds[pos.1]; + let next_row = if pos.0 == bounds.1 { + bounds.0 + } else { + pos.0 + 1 + }; + (next_row, pos.1) + } + }; + + if grid.grid[next_pos.0][next_pos.1].unwrap() { + // We're about to hit a wall + break; + } + pos = next_pos; + } + + Pose { + pos, + orientation: pose.orientation, + } + } + } +} diff --git a/src/day9.rs b/src/day9.rs index 1e8c1d8..52e60e8 100644 --- a/src/day9.rs +++ b/src/day9.rs @@ -1,12 +1,6 @@ use std::collections::HashSet; -#[derive(Debug)] -pub enum Dir { - Left, - Right, - Up, - Down, -} +use crate::util::Dir; pub type Motion = (Dir, usize); diff --git a/src/lib.rs b/src/lib.rs index 7658860..00d4a16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ pub mod day19; pub mod day2; pub mod day20; pub mod day21; +pub mod day22; pub mod day3; pub mod day4; pub mod day5; diff --git a/src/util.rs b/src/util.rs index ca64002..8f7d517 100644 --- a/src/util.rs +++ b/src/util.rs @@ -122,3 +122,34 @@ where best } + +#[derive(Debug, Clone, Copy)] +pub enum Dir { + Right = 0, + Down, + Left, + Up, +} + +impl Dir { + pub fn from_usize(n: usize) -> Option { + match n { + 0 => Some(Dir::Right), + 1 => Some(Dir::Down), + 2 => Some(Dir::Left), + 3 => Some(Dir::Up), + _ => None, + } + } + + pub fn cw(&self) -> Dir { + let d = *self as usize; + Self::from_usize((d + 1) % 4).unwrap() + } + + pub fn ccw(&self) -> Dir { + let d = *self as usize; + // Add 3 instead of subtracting one to avoid negative numbers + Self::from_usize((d + 3) % 4).unwrap() + } +}