Day 22, part 1
This commit is contained in:
		
							
								
								
									
										18
									
								
								src/bin/d22p1.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/bin/d22p1.rs
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										188
									
								
								src/day22.rs
									
									
									
									
									
										Normal 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,
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,12 +1,6 @@
 | 
				
			|||||||
use std::collections::HashSet;
 | 
					use std::collections::HashSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					use crate::util::Dir;
 | 
				
			||||||
pub enum Dir {
 | 
					 | 
				
			||||||
    Left,
 | 
					 | 
				
			||||||
    Right,
 | 
					 | 
				
			||||||
    Up,
 | 
					 | 
				
			||||||
    Down,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub type Motion = (Dir, usize);
 | 
					pub type Motion = (Dir, usize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@ pub mod day19;
 | 
				
			|||||||
pub mod day2;
 | 
					pub mod day2;
 | 
				
			||||||
pub mod day20;
 | 
					pub mod day20;
 | 
				
			||||||
pub mod day21;
 | 
					pub mod day21;
 | 
				
			||||||
 | 
					pub mod day22;
 | 
				
			||||||
pub mod day3;
 | 
					pub mod day3;
 | 
				
			||||||
pub mod day4;
 | 
					pub mod day4;
 | 
				
			||||||
pub mod day5;
 | 
					pub mod day5;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										31
									
								
								src/util.rs
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								src/util.rs
									
									
									
									
									
								
							@ -122,3 +122,34 @@ where
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    best
 | 
					    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()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user