diff --git a/2022/src/bin/day22.rs b/2022/src/bin/day22.rs index 7b22e8d..c648b6c 100644 --- a/2022/src/bin/day22.rs +++ b/2022/src/bin/day22.rs @@ -1,19 +1,36 @@ #![feature(test)] extern crate test; +use std::fmt; + use aoc2022::{ boilerplate, common::*, - grid::{Grid, HashGrid, PositionND}, + grid::{draw_ascii, Direction, Grid, HashGrid, PositionND}, }; const DAY: usize = 22; -type Parsed = (HashGrid, Vec); +type Parsed = (HashGrid, Vec<(i64, Turn)>); + +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +enum Field { + Empty = b'.' as isize, + Wall = b'#' as isize, + Me = b'O' as isize, // for debug printing the grid + #[default] + Missing = b' ' as isize, +} + +impl fmt::Display for Field { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", *self as u8 as char) + } +} #[derive(Copy, Clone, Debug)] -enum Instruction { - TurnLeft, - TurnRight, - Step(usize), +enum Turn { + Left, + Right, + None, } fn parse_input(raw: &str) -> Parsed { @@ -21,17 +38,66 @@ fn parse_input(raw: &str) -> Parsed { let grid = maze .lines() .zip(1..) - .flat_map(|(line, x)| line.bytes().zip(1..).filter(|(b, _)| *b != b' ').map(move |(b, y)| (PositionND::from([x, y]), b == b'#'))) + .flat_map(|(line, x)| { + line.bytes().zip(1..).filter(|(b, _)| *b != b' ').map(move |(b, y)| { + let f = match b { + b'.' => Field::Empty, + b'#' => Field::Wall, + _ => unreachable!(), + }; + (PositionND::from([x, y]), f) + }) + }) .collect(); let moves = moves .split_inclusive(['L', 'R']) .map(|s| s.split_at(s.len() - 1)) - .flat_map(|(n, d)| [Instruction::Step(parse_num(n)), if d == "L" { Instruction::TurnLeft } else { Instruction::TurnRight }]) + .map(|(n, d)| if n == "" { (parse_num(d), Turn::None) } else { (parse_num(n), if d == "L" { Turn::Left } else { Turn::Right }) }) .collect(); (grid, moves) } -fn part1(parsed: &Parsed) -> usize { - unimplemented!() +fn part1((grid, instructions): &Parsed) -> i64 { + let mut pos = *grid.fields.keys().filter(|p| p.0[0] == 1).min_by_key(|p| p.0[1]).unwrap(); + let mut dir = Direction::Right; + let mut grid2 = grid.clone(); + grid2[pos] = Field::Me; + println!("{}", draw_ascii(&grid2.fields)); + for &(steps, turn) in instructions { + for _ in 0..steps { + let next = PositionND::from(match dir { + Direction::Up => [-1, 0], + Direction::Down => [1, 0], + Direction::Left => [0, -1], + Direction::Right => [0, 1], + }) + pos; + // dbg!(steps, pos, dir, next); + pos = match grid.get(&next) { + Some(Field::Wall) => break, + Some(_) => next, + None => { + println!("Wrapping from {pos:?} in direction {dir:?}"); + let (&new_pos, &wall) = match dir { + Direction::Up => grid.fields.iter().filter(|(p, _)| p.0[1] == pos.0[1]).max_by_key(|(p, _)| p.0[0]), + Direction::Down => grid.fields.iter().filter(|(p, _)| p.0[1] == pos.0[1]).min_by_key(|(p, _)| p.0[0]), + Direction::Left => grid.fields.iter().filter(|(p, _)| p.0[0] == pos.0[0]).max_by_key(|(p, _)| p.0[1]), + Direction::Right => grid.fields.iter().filter(|(p, _)| p.0[0] == pos.0[0]).min_by_key(|(p, _)| p.0[1]), + } + .unwrap(); + if wall == Field::Wall { + break; + } else { + new_pos + } + } + } + } + dir = match (dir, turn) { + (_, Turn::None) => break, + (d, Turn::Right) => d + 1, + (d, Turn::Left) => d + -1, + }; + } + pos.0[0] * 1000 + pos.0[1] * 4 + (dir as i64) } fn part2(parsed: &Parsed) -> usize { @@ -39,8 +105,7 @@ fn part2(parsed: &Parsed) -> usize { } boilerplate! { - TEST_INPUT == "\ - ...# + TEST_INPUT == " ...# .#.. #... .... @@ -55,10 +120,10 @@ boilerplate! { 10R5L5R10L4R5L5", tests: { - part1: { TEST_INPUT => 0 }, + part1: { TEST_INPUT => 6032 }, part2: { TEST_INPUT => 0 }, }, - bench1 == 0, + bench1 == 0, // 123047 too high bench2 == 0, - bench_parse: |(g, i): &Parsed| g.len() + i.len() => 19002, + bench_parse: |(g, i): &Parsed| g.len() + i.len() => 17001, } diff --git a/2022/src/grid.rs b/2022/src/grid.rs index 1981cd6..f454b38 100644 --- a/2022/src/grid.rs +++ b/2022/src/grid.rs @@ -1,12 +1,11 @@ pub mod direction; pub mod position; pub use direction::*; +use fnv::FnvHashMap as HashMap; use itertools::{join, Itertools, MinMaxResult}; pub use position::*; use std::{ - collections::HashMap, fmt::Display, - hash::BuildHasher, ops::{Index, IndexMut}, }; @@ -126,7 +125,7 @@ pub fn get_boundaries(input: &[&PositionND<2>]) -> Boundaries { Boundaries { x_min, x_max, y_min, y_max } } -pub fn draw_ascii(coordinates: &HashMap, T, S>) -> String { +pub fn draw_ascii(coordinates: &HashMap, T>) -> String { let b = get_boundaries(&coordinates.keys().collect::>()); join( (b.y_min..=b.y_max).rev().map(|y| { diff --git a/2022/src/grid/direction.rs b/2022/src/grid/direction.rs index 423b223..9c4360b 100644 --- a/2022/src/grid/direction.rs +++ b/2022/src/grid/direction.rs @@ -5,10 +5,10 @@ pub const ALL_DIRECTIONS: [Direction; 4] = [Direction::Up, Direction::Down, Dire #[derive(Clone, Copy, Debug)] pub enum Direction { - Up, - Down, - Left, - Right, + Right = 0, + Down = 1, + Left = 2, + Up = 3, } impl AddAssign for Direction {