summaryrefslogtreecommitdiff
path: root/2022/src/bin/day_22.rs
diff options
context:
space:
mode:
authorJustin Wernick <j.wernick@eyeo.com>2022-12-22 15:47:33 +0200
committerJustin Wernick <j.wernick@eyeo.com>2022-12-22 15:47:33 +0200
commit28d21df097a3682d7598e5454ca7d4020cb19ab9 (patch)
treee469f62d15c781758655a07a24b3a1e35b0f8c42 /2022/src/bin/day_22.rs
parente7bca77f9bd9f001c9c2dfd9ae48ca764a082325 (diff)
Day 22 part 1
Diffstat (limited to '2022/src/bin/day_22.rs')
-rw-r--r--2022/src/bin/day_22.rs224
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,
+ }
+ }
+}