Day 22, part 2
This commit is contained in:
parent
ae143d4c57
commit
62c866abf9
@ -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
40
src/bin/d22p2.rs
Normal 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);
|
||||
}
|
397
src/day22.rs
397
src/day22.rs
@ -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>) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user