Day 22, part 2
This commit is contained in:
parent
ae143d4c57
commit
62c866abf9
@ -9,7 +9,7 @@ pub fn main() {
|
|||||||
// dbg!(&grid);
|
// dbg!(&grid);
|
||||||
// dbg!(&instructions);
|
// dbg!(&instructions);
|
||||||
|
|
||||||
let mut pose = day22::Pose::new(&grid);
|
let mut pose = grid.initial_pose();
|
||||||
// dbg!(&pose);
|
// dbg!(&pose);
|
||||||
for inst in &instructions {
|
for inst in &instructions {
|
||||||
pose = grid.exec_instruction(&pose, inst).0;
|
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 itertools::Itertools;
|
||||||
|
|
||||||
use crate::util::Dir;
|
use crate::util::Dir;
|
||||||
@ -20,19 +22,7 @@ pub struct Pose {
|
|||||||
pub orientation: Dir,
|
pub orientation: Dir,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pose {
|
#[derive(Debug)]
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum MoveResult {
|
pub enum MoveResult {
|
||||||
Blocked,
|
Blocked,
|
||||||
BlockedByWrapping,
|
BlockedByWrapping,
|
||||||
@ -63,6 +53,7 @@ pub trait Navigable {
|
|||||||
from: &Self::Pose,
|
from: &Self::Pose,
|
||||||
inst: &Self::NavigationInstruction,
|
inst: &Self::NavigationInstruction,
|
||||||
) -> (Self::Pose, MoveResult);
|
) -> (Self::Pose, MoveResult);
|
||||||
|
fn initial_pose(&self) -> Self::Pose;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -74,6 +65,40 @@ pub struct SparseGrid {
|
|||||||
pub col_bounds: Vec<(usize, usize)>,
|
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 {
|
impl Navigable for SparseGrid {
|
||||||
type Pose = Pose;
|
type Pose = Pose;
|
||||||
type NavigationInstruction = PassInstr;
|
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>) {
|
pub fn parse_map_and_path(input: &str) -> (SparseGrid, Vec<PassInstr>) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user