diff options
Diffstat (limited to '2022/src/bin')
-rw-r--r-- | 2022/src/bin/day_22.rs | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/2022/src/bin/day_22.rs b/2022/src/bin/day_22.rs new file mode 100644 index 0000000..693164d --- /dev/null +++ b/2022/src/bin/day_22.rs @@ -0,0 +1,224 @@ +use nom::{ + branch::alt, + bytes::complete::tag, + character::complete::{line_ending, u32}, + combinator::{map, value}, + multi::{many1, separated_list1}, + sequence::tuple, + IResult, +}; +use std::fs; + +fn main() -> Result<(), Box<dyn std::error::Error>> { + let input = fs::read_to_string("inputs/day_22.txt")?; + let parsed = Input::parser(&input).unwrap().1; + + dbg!(State::walk_the_map(&parsed)); + dbg!(State::walk_the_map(&parsed).score()); + + Ok(()) +} + +#[derive(Debug, Clone)] +struct Input { + map: Map, + instructions: Vec<Instruction>, +} + +#[derive(Debug, Clone)] +struct Map(Vec<Vec<MapPoint>>); + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum MapPoint { + Wall, + Empty, + Void, +} + +#[derive(Debug, Clone)] +enum Instruction { + TurnLeft, + TurnRight, + Walk(u32), +} + +impl Input { + fn parser(input: &str) -> IResult<&str, Self> { + map( + tuple(( + Map::parser, + line_ending, + line_ending, + many1(Instruction::parser), + )), + |(map, _, _, instructions)| Input { map, instructions }, + )(input) + } +} + +impl Map { + fn parser(input: &str) -> IResult<&str, Self> { + map(separated_list1(line_ending, many1(MapPoint::parser)), Map)(input) + } +} + +impl MapPoint { + fn parser(input: &str) -> IResult<&str, Self> { + alt(( + value(MapPoint::Wall, tag("#")), + value(MapPoint::Empty, tag(".")), + value(MapPoint::Void, tag(" ")), + ))(input) + } +} + +impl Instruction { + fn parser(input: &str) -> IResult<&str, Self> { + alt(( + value(Instruction::TurnLeft, tag("L")), + value(Instruction::TurnRight, tag("R")), + map(u32, Instruction::Walk), + ))(input) + } +} + +#[derive(Debug, Clone)] +struct State { + position: Point, + facing: Direction, +} + +#[derive(Debug, Clone)] +struct Point { + x: usize, + y: usize, +} + +#[derive(Debug, Clone)] +enum Direction { + Right, + Down, + Left, + Up, +} + +impl State { + fn walk_the_map(input: &Input) -> State { + let mut state = State::spawn(&input.map); + for instruction in &input.instructions { + state.process_instruction(&input.map, &instruction); + dbg!((&instruction, &state)); + } + state + } + + fn spawn(map: &Map) -> State { + let y = 0; + let x = map.0[y].iter().position(|p| p == &MapPoint::Empty).unwrap(); + State { + position: Point { x, y }, + facing: Direction::Right, + } + } + + fn process_instruction(&mut self, map: &Map, instruction: &Instruction) { + match instruction { + Instruction::TurnLeft => { + self.facing = self.facing.spin_left(); + } + Instruction::TurnRight => { + self.facing = self.facing.spin_right(); + } + Instruction::Walk(amount) => { + for _ in 0..*amount { + let mut next_point = self.position.clone(); + + let mut made_a_step = false; + let mut hit_a_wall = false; + while !made_a_step && !hit_a_wall { + let peek = match self.facing { + Direction::Right => Point { + x: if next_point.x < map.0[next_point.y].len() - 1 { + next_point.x + 1 + } else { + 0 + }, + ..next_point + }, + Direction::Left => Point { + x: if next_point.x > 0 { + next_point.x - 1 + } else { + map.0[next_point.y].len() - 1 + }, + ..next_point + }, + Direction::Down => Point { + y: if next_point.y < map.0.len() - 1 { + next_point.y + 1 + } else { + 0 + }, + ..next_point + }, + Direction::Up => Point { + y: if next_point.y > 0 { + next_point.y - 1 + } else { + map.0.len() - 1 + }, + ..next_point + }, + }; + + let peek_value = map.0[peek.y].get(peek.x); + match peek_value { + Some(MapPoint::Empty) => { + next_point = peek; + made_a_step = true; + } + Some(MapPoint::Void) | None => { + next_point = peek; + } + Some(MapPoint::Wall) => { + hit_a_wall = true; + } + } + } + + if !hit_a_wall { + self.position = next_point; + } + } + } + } + } + + fn score(&self) -> usize { + (self.position.y + 1) * 1000 + (self.position.x + 1) * 4 + self.facing.score() + } +} + +impl Direction { + fn spin_left(&self) -> Direction { + match self { + Direction::Right => Direction::Up, + Direction::Down => Direction::Right, + Direction::Left => Direction::Down, + Direction::Up => Direction::Left, + } + } + + fn spin_right(&self) -> Direction { + self.spin_left().spin_left().spin_left() + } + + fn score(&self) -> usize { + match self { + Direction::Right => 0, + Direction::Down => 1, + Direction::Left => 2, + Direction::Up => 3, + } + } +} |