Skip to main content

year2016/
day01.rs

1use utils::geometry::Vec2;
2use utils::hash::FastSet;
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 = Vec2::ORIGIN;
30        let mut dir = Vec2::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 total = self
46            .instructions
47            .iter()
48            .map(|&(_, steps)| usize::from(steps))
49            .sum();
50        let mut visited = FastSet::with_capacity(total);
51        let mut pos: Vec2<i32> = Vec2::ORIGIN;
52        let mut dir = Vec2::UP;
53
54        for &(turn, steps) in &self.instructions {
55            dir = match turn {
56                Turn::L => dir.turn_left(),
57                Turn::R => dir.turn_right(),
58            };
59            for _ in 0..steps {
60                pos += dir;
61                if !visited.insert(pos) {
62                    return pos.manhattan_distance();
63                }
64            }
65        }
66
67        panic!("no location visited twice");
68    }
69}
70
71examples!(Day01 -> (u32, u32) [
72    {input: "R2, L3", part1: 5},
73    {input: "R2, R2, R2", part1: 2},
74    {input: "R5, L5, R5, R3", part1: 12},
75    {input: "R8, R4, R4, R8", part2: 4},
76]);