year2015/
day03.rs

1use std::collections::HashSet;
2use utils::point::Point2D;
3use utils::prelude::*;
4
5/// Counting unique points.
6#[derive(Clone, Debug)]
7pub struct Day03 {
8    directions: Vec<Point2D<i32>>,
9}
10
11impl Day03 {
12    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13        Ok(Self {
14            directions: input
15                .chars()
16                .map(|c| match c {
17                    '^' => Ok(Point2D::UP),
18                    '>' => Ok(Point2D::RIGHT),
19                    'v' => Ok(Point2D::DOWN),
20                    '<' => Ok(Point2D::LEFT),
21                    _ => Err(InputError::new(input, c, "expected one of ^>v<")),
22                })
23                .collect::<Result<Vec<Point2D<i32>>, InputError>>()?,
24        })
25    }
26
27    #[must_use]
28    pub fn part1(&self) -> usize {
29        let mut pos = Point2D::default();
30
31        self.count_positions(|dir| {
32            pos += dir;
33            pos
34        })
35    }
36
37    #[must_use]
38    pub fn part2(&self) -> usize {
39        let (mut pos1, mut pos2) = Default::default();
40
41        self.count_positions(|dir| {
42            (pos1, pos2) = (pos2, pos1);
43            pos1 += dir;
44            pos1
45        })
46    }
47
48    fn count_positions(&self, mut f: impl FnMut(Point2D<i32>) -> Point2D<i32>) -> usize {
49        let mut set = HashSet::with_capacity(self.directions.len());
50        set.insert(Point2D::default());
51
52        for &dir in &self.directions {
53            set.insert(f(dir));
54        }
55
56        set.len()
57    }
58}
59
60examples!(Day03 -> (usize, usize) [
61    {input: ">", part1: 2},
62    {input: "^>", part2: 3},
63    {input: "^>v<", part1: 4, part2: 3},
64    {input: "^v^v^v^v^v", part1: 2, part2: 11},
65]);