Day 22, part 1

This commit is contained in:
jazzpi 2022-12-22 12:57:38 +01:00
parent a0fa5256e9
commit 5e6870d092
5 changed files with 239 additions and 7 deletions

18
src/bin/d22p1.rs Normal file
View File

@ -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);
}

188
src/day22.rs Normal file
View File

@ -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<Vec<Option<bool>>>,
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<Instruction>) {
let lines = input.lines().collect_vec();
let mut grid: Vec<Vec<Option<bool>>> = 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,
}
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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<Dir> {
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()
}
}