summaryrefslogtreecommitdiff
path: root/src/day_2.rs
blob: d7ebcd0c8d613fa6fabb6d9d2a2173b59ff343b1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use std::ops::AddAssign;

type Scalar = isize;

#[derive(Copy, Clone, Debug)]
enum Instruction
{
    Forward(Scalar),
    Down(Scalar),
    Up(Scalar),
}

#[derive(Copy, Clone, Debug)]
struct Victor
{
    x: Scalar,
    y: Scalar,
}

fn part1(instructions: &[Instruction])
{
    let directions: Vec<Victor> = instructions
        .iter()
        .map(|&i| Victor::from_direct_instruction(i))
        .collect();

    let mut position = Victor::new(0, 0);
    for dir in directions {
        position += dir;
    }

    println!("Solution to part 1: {}", position.x * position.y);
}

fn part2(instructions: &[Instruction])
{
    let mut aim: Scalar = 0;
    let mut position = Victor::new(0, 0);

    for i in instructions {
        match &i {
            Instruction::Down(amount) => aim += amount,
            Instruction::Up(amount) => aim -= amount,
            Instruction::Forward(amount) => position += Victor::new(*amount, amount * aim),
        }
    }

    println!("Solution to part 2: {}", position.x * position.y);
}

pub fn run(input: Vec<String>)
{
    let instructions: Vec<Instruction> = input
        .into_iter()
        .map(|s| Instruction::from_str(s))
        .collect();

    part1(&instructions);
    part2(&instructions);
}

impl Instruction
{
    pub fn from_str<S>(instruction_str: S) -> Self
    where
        S: AsRef<str>,
    {
        let parts: Vec<&str> = instruction_str.as_ref().split_whitespace().collect();
        assert_eq!(parts.len(), 2);

        let scalar = parts[1].parse().expect("Not a valid length");
        match parts[0] {
            "forward" => Self::Forward(scalar),
            "down" => Self::Down(scalar),
            "up" => Self::Up(scalar),
            o => panic!("{} is not a valid instruction", o),
        }
    }
}

impl Victor
{
    pub fn new(x: Scalar, y: Scalar) -> Self { Self { x, y } }

    pub fn from_direct_instruction(instruction: Instruction) -> Self
    {
        use Instruction::*;

        match instruction {
            Forward(distance) => Victor::new(distance, 0),
            Down(distance) => Victor::new(0, distance),
            Up(distance) => Victor::new(0, -distance),
        }
    }
}

impl AddAssign for Victor
{
    fn add_assign(&mut self, rhs: Self)
    {
        self.x += rhs.x;
        self.y += rhs.y;
    }
}