Day 22, part 2

This commit is contained in:
jazzpi 2022-12-22 17:21:06 +01:00
parent ae143d4c57
commit 62c866abf9
3 changed files with 425 additions and 14 deletions

View File

@ -9,7 +9,7 @@ pub fn main() {
// dbg!(&grid);
// dbg!(&instructions);
let mut pose = day22::Pose::new(&grid);
let mut pose = grid.initial_pose();
// dbg!(&pose);
for inst in &instructions {
pose = grid.exec_instruction(&pose, inst).0;

40
src/bin/d22p2.rs Normal file
View File

@ -0,0 +1,40 @@
use std::collections::HashMap;
use aoc22::{
day22::{self, CubeSide, Navigable},
util,
};
pub fn main() {
let (grid, instructions) = day22::parse_map_and_path(&util::parse_input());
let mut pattern = HashMap::new();
pattern.insert(CubeSide::Top, (0, 1));
pattern.insert(CubeSide::Fore, (1, 1));
pattern.insert(CubeSide::Left, (2, 0));
pattern.insert(CubeSide::Back, (3, 0));
pattern.insert(CubeSide::Bottom, (2, 1));
pattern.insert(CubeSide::Right, (0, 2));
// Pattern for example input
// WARNING: CubeGrid::wrap_around is hardcoded for the pattern above
// pattern.insert(CubeSide::Top, (0, 2));
// pattern.insert(CubeSide::Fore, (1, 2));
// pattern.insert(CubeSide::Left, (1, 1));
// pattern.insert(CubeSide::Back, (1, 0));
// pattern.insert(CubeSide::Bottom, (2, 2));
// pattern.insert(CubeSide::Right, (2, 3));
let grid = day22::CubeGrid::from(&grid, &pattern);
let mut pose = grid.initial_pose();
for inst in &instructions {
pose = grid.exec_instruction(&pose, inst).0;
}
let pos = pose.1.pos;
let row_add = pattern[&pose.0].0 * grid.side_height;
let col_add = pattern[&pose.0].1 * grid.side_width;
let pass =
1000 * (row_add + pos.0 + 1) + 4 * (col_add + pos.1 + 1) + (pose.1.orientation as usize);
println!("Passowrd: {}", pass);
}

View File

@ -1,3 +1,5 @@
use std::collections::HashMap;
use itertools::Itertools;
use crate::util::Dir;
@ -20,19 +22,7 @@ pub struct Pose {
pub orientation: Dir,
}
impl Pose {
pub fn new(grid: &SparseGrid) -> 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,
}
}
}
#[derive(Debug)]
pub enum MoveResult {
Blocked,
BlockedByWrapping,
@ -63,6 +53,7 @@ pub trait Navigable {
from: &Self::Pose,
inst: &Self::NavigationInstruction,
) -> (Self::Pose, MoveResult);
fn initial_pose(&self) -> Self::Pose;
}
#[derive(Debug)]
@ -74,6 +65,40 @@ pub struct SparseGrid {
pub col_bounds: Vec<(usize, usize)>,
}
impl SparseGrid {
fn print(&self, pose: Option<&Pose>) {
let check_pos = |y, x| {
if let Some(pose) = pose {
pose.pos.0 == y && pose.pos.1 == x
} else {
false
}
};
for (y, row) in self.grid.iter().enumerate() {
for (x, col) in row.iter().enumerate() {
let c = if check_pos(y, x) {
assert!(*col == Some(false));
match pose.unwrap().orientation {
Dir::Right => '>',
Dir::Down => 'v',
Dir::Left => '<',
Dir::Up => '^',
}
} else if col.is_none() {
' '
} else if *col == Some(true) {
'#'
} else {
'.'
};
print!("{}", c);
}
print!("\n");
}
}
}
impl Navigable for SparseGrid {
type Pose = Pose;
type NavigationInstruction = PassInstr;
@ -159,6 +184,352 @@ impl Navigable for SparseGrid {
),
}
}
fn initial_pose(&self) -> Self::Pose {
let col = self.grid[0]
.iter()
.position(|t| if let Some(occ) = t { !occ } else { false })
.unwrap();
Pose {
pos: (0, col),
orientation: Dir::Right,
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum CubeSide {
Top,
Bottom,
Left,
Right,
Fore,
Back,
}
#[derive(Debug)]
pub struct CubeGrid {
// The side grids don't have to be sparse, but we don't have a dense
// implementation...
pub sides: HashMap<CubeSide, SparseGrid>,
pub side_height: usize,
pub side_width: usize,
}
impl CubeGrid {
pub fn from(sparse: &SparseGrid, pattern: &HashMap<CubeSide, (usize, usize)>) -> CubeGrid {
let fold_width = pattern.values().map(|(_, col)| col).max().unwrap() + 1;
let fold_height = pattern.values().map(|(row, _)| row).max().unwrap() + 1;
let side_width = sparse.width / fold_width;
assert!(sparse.width % fold_width == 0);
let side_height = sparse.height / fold_height;
assert!(sparse.height % fold_height == 0);
let mut sides = HashMap::new();
for (side, (fold_row, fold_col)) in pattern {
let mut grid = Vec::new();
for r in 0..side_height {
let mut row = Vec::new();
for c in 0..side_width {
let tile = sparse.grid[fold_row * side_height + r][fold_col * side_width + c];
assert!(tile.is_some());
row.push(tile);
}
grid.push(row);
}
let grid = SparseGrid {
grid,
height: side_height,
width: side_width,
row_bounds: vec![(0, side_width - 1); side_height],
col_bounds: vec![(0, side_height - 1); side_width],
};
assert!(sides.insert(*side, grid).is_none());
}
CubeGrid {
sides,
side_height,
side_width,
}
}
pub fn print(&self, pose: &(CubeSide, Pose)) {
for (side, grid) in &self.sides {
if pose.0 != *side {
continue;
}
println!("{:?}:", side);
grid.print(Some(&pose.1));
println!("");
}
}
fn wrap_around(&self, side: CubeSide, pose: &Pose) -> (CubeSide, Pose) {
// FIXME: This is hardcoded for the folding pattern of the actual input.
// It won't work for the example input.
assert_eq!(self.side_height, self.side_width);
let dir = pose.orientation;
let pos = pose.pos;
let row = pos.0;
let last = self.side_height - 1;
let row_inv = last - row;
let col = pos.1;
match side {
CubeSide::Top => match dir {
Dir::Right => (
CubeSide::Right,
Pose {
pos: (row, 0),
orientation: Dir::Right,
},
),
Dir::Down => (
CubeSide::Fore,
Pose {
pos: (0, col),
orientation: Dir::Down,
},
),
Dir::Left => (
CubeSide::Left,
Pose {
pos: (row_inv, 0),
orientation: Dir::Right,
},
),
Dir::Up => (
CubeSide::Back,
Pose {
pos: (col, 0),
orientation: Dir::Right,
},
),
},
CubeSide::Bottom => match dir {
Dir::Right => (
CubeSide::Right,
Pose {
pos: (row_inv, last),
orientation: Dir::Left,
},
),
Dir::Down => (
CubeSide::Back,
Pose {
pos: (col, last),
orientation: Dir::Left,
},
),
Dir::Left => (
CubeSide::Left,
Pose {
pos: (row, last),
orientation: Dir::Left,
},
),
Dir::Up => (
CubeSide::Fore,
Pose {
pos: (last, col),
orientation: Dir::Up,
},
),
},
CubeSide::Left => match dir {
Dir::Right => (
CubeSide::Bottom,
Pose {
pos: (row, 0),
orientation: Dir::Right,
},
),
Dir::Down => (
CubeSide::Back,
Pose {
pos: (0, col),
orientation: Dir::Down,
},
),
Dir::Left => (
CubeSide::Top,
Pose {
pos: (row_inv, 0),
orientation: Dir::Right,
},
),
Dir::Up => (
CubeSide::Fore,
Pose {
pos: (col, 0),
orientation: Dir::Right,
},
),
},
CubeSide::Right => match dir {
Dir::Right => (
CubeSide::Bottom,
Pose {
pos: (row_inv, last),
orientation: Dir::Left,
},
),
Dir::Down => (
CubeSide::Fore,
Pose {
pos: (col, last),
orientation: Dir::Left,
},
),
Dir::Left => (
CubeSide::Top,
Pose {
pos: (row, last),
orientation: Dir::Left,
},
),
Dir::Up => (
CubeSide::Back,
Pose {
pos: (last, col),
orientation: Dir::Up,
},
),
},
CubeSide::Fore => match dir {
Dir::Right => (
CubeSide::Right,
Pose {
pos: (last, row),
orientation: Dir::Up,
},
),
Dir::Down => (
CubeSide::Bottom,
Pose {
pos: (0, col),
orientation: Dir::Down,
},
),
Dir::Left => (
CubeSide::Left,
Pose {
pos: (0, row),
orientation: Dir::Down,
},
),
Dir::Up => (
CubeSide::Top,
Pose {
pos: (last, col),
orientation: Dir::Up,
},
),
},
CubeSide::Back => match dir {
Dir::Right => (
CubeSide::Bottom,
Pose {
pos: (last, row),
orientation: Dir::Up,
},
),
Dir::Down => (
CubeSide::Right,
Pose {
pos: (0, col),
orientation: Dir::Down,
},
),
Dir::Left => (
CubeSide::Top,
Pose {
pos: (0, row),
orientation: Dir::Down,
},
),
Dir::Up => (
CubeSide::Left,
Pose {
pos: (last, col),
orientation: Dir::Up,
},
),
},
}
}
}
impl Navigable for CubeGrid {
type Pose = (CubeSide, Pose);
type NavigationInstruction = PassInstr;
fn forward(
&self,
(from_side, from_pose): &Self::Pose,
steps: usize,
) -> (Self::Pose, MoveResult) {
let mut side = from_side.clone();
let mut pose = from_pose.clone();
let mut status = MoveResult::Success;
for _ in 0..steps {
let (next_pose, res) = self.sides[&side].forward(&pose, 1);
if res.wrapped_around() {
let (next_side, next_pose) = self.wrap_around(side, &pose);
if self.sides[&next_side].grid[next_pose.pos.0][next_pose.pos.1] == Some(true) {
// Can't wrap around, we're blocked
return ((side, pose), MoveResult::BlockedByWrapping);
}
side = next_side;
pose = next_pose;
status = MoveResult::WrappedAround;
} else if res.was_blocked() {
return ((side, pose), MoveResult::Blocked);
} else {
pose = next_pose;
}
}
((side, pose), status)
}
fn exec_instruction(
&self,
from: &Self::Pose,
inst: &Self::NavigationInstruction,
) -> (Self::Pose, MoveResult) {
match inst {
PassInstr::Move(n) => self.forward(from, *n),
PassInstr::Turn(dir) => (
(
from.0,
Pose {
pos: from.1.pos,
orientation: match dir {
TurnDir::CW => from.1.orientation.cw(),
TurnDir::CCW => from.1.orientation.ccw(),
},
},
),
MoveResult::Success,
),
}
}
fn initial_pose(&self) -> Self::Pose {
let col = self.sides[&CubeSide::Top].grid[0]
.iter()
.position(|t| *t == Some(false))
.unwrap();
(
CubeSide::Top,
Pose {
pos: (0, col),
orientation: Dir::Right,
},
)
}
}
pub fn parse_map_and_path(input: &str) -> (SparseGrid, Vec<PassInstr>) {