year2016/
day01.rs

1use std::collections::HashSet;
2use utils::point::Point2D;
3use utils::prelude::*;
4
5/// Calculating Manhattan distance.
6#[derive(Clone, Debug)]
7pub struct Day01 {
8    instructions: Vec<(Turn, u16)>,
9}
10
11#[derive(Copy, Clone, Eq, PartialEq, Debug)]
12enum Turn {
13    L,
14    R,
15}
16
17impl Day01 {
18    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
19        Ok(Self {
20            instructions: parser::literal_map!("L" => Turn::L, "R" => Turn::R)
21                .then(parser::u16())
22                .with_suffix(", ".or(parser::eof()))
23                .parse_all(input)?,
24        })
25    }
26
27    #[must_use]
28    pub fn part1(&self) -> u32 {
29        let mut pos = Point2D::ORIGIN;
30        let mut dir = Point2D::UP;
31
32        for &(turn, steps) in &self.instructions {
33            dir = match turn {
34                Turn::L => dir.turn_left(),
35                Turn::R => dir.turn_right(),
36            };
37            pos += dir * i32::from(steps);
38        }
39
40        pos.manhattan_distance()
41    }
42
43    #[must_use]
44    pub fn part2(&self) -> u32 {
45        let mut pos: Point2D<i32> = Point2D::ORIGIN;
46        let mut dir = Point2D::UP;
47        let mut visited = HashSet::new();
48
49        for &(turn, steps) in &self.instructions {
50            dir = match turn {
51                Turn::L => dir.turn_left(),
52                Turn::R => dir.turn_right(),
53            };
54            for _ in 0..steps {
55                pos += dir;
56                if !visited.insert(pos) {
57                    return pos.manhattan_distance();
58                }
59            }
60        }
61
62        panic!("no location visited twice");
63    }
64}
65
66examples!(Day01 -> (u32, u32) [
67    {input: "R2, L3", part1: 5},
68    {input: "R2, R2, R2", part1: 2},
69    {input: "R5, L5, R5, R3", part1: 12},
70    {input: "R8, R4, R4, R8", part2: 4},
71]);