summaryrefslogtreecommitdiff
path: root/src/bin/day13.rs
blob: 4536aabeb5432a5acb34a1bd3ac5252dd84a498e (plain)
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
105
106
107
use regex::Regex;

static DAY: u8 = 13;

fn main() {
    let input = advent::read_file(DAY);
    println!("{DAY}a: {}", win_tokens(input.trim_end()));
    println!("{DAY}b: {}", win_tokens_big(input.trim_end()));
}

struct Machine {
    button_a: (i64, i64),
    button_b: (i64, i64),
    prize: (i64, i64),
}

impl Machine {
    fn new(input: &str) -> Machine {
        let re_a = Regex::new(r"Button A: X\+(\d+), Y\+(\d+)").unwrap();
        let re_b = Regex::new(r"Button B: X\+(\d+), Y\+(\d+)").unwrap();
        let re_p = Regex::new(r"Prize: X=(\d+), Y=(\d+)").unwrap();

        let lines = input.split("\n").collect::<Vec<_>>();
        let button_a = lines[0];
        let button_b = lines[1];
        let prizes = lines[2];

        let captures_a = re_a.captures(button_a).unwrap();
        let captures_b = re_b.captures(button_b).unwrap();
        let captures_p = re_p.captures(prizes).unwrap();

        let a_x = captures_a.get(1).unwrap().as_str().parse::<i64>().unwrap();
        let a_y = captures_a.get(2).unwrap().as_str().parse::<i64>().unwrap();
        let b_x = captures_b.get(1).unwrap().as_str().parse::<i64>().unwrap();
        let b_y = captures_b.get(2).unwrap().as_str().parse::<i64>().unwrap();
        let p_x = captures_p.get(1).unwrap().as_str().parse::<i64>().unwrap();
        let p_y = captures_p.get(2).unwrap().as_str().parse::<i64>().unwrap();

        Machine {
            button_a: (a_x, a_y),
            button_b: (b_x, b_y),
            prize: (p_x, p_y),
        }
    }

    fn lowest_prize(&self) -> Option<i64> {
        let dividend = (self.prize.0 * self.button_a.1) - (self.prize.1 * self.button_a.0);
        let divisor = (self.button_b.0 * self.button_a.1) - (self.button_b.1 * self.button_a.0);
        if divisor == 0 || (dividend % divisor != 0) {
            return None
        }
        let b = dividend / divisor;

        let dividend = self.prize.0 - (b * self.button_b.0);
        let divisor = self.button_a.0;
        if divisor == 0 || (dividend % divisor != 0) {
            return None;
        }
        let a = dividend / divisor;

        Some(3 * a + b)
    }
}

fn win_tokens(input: &str) -> i64 {
    input.split("\n\n")
         .map(Machine::new)
         .map(|machine| machine.lowest_prize().unwrap_or(0))
         .sum()
}

fn win_tokens_big(input: &str) -> i64 {
    input.split("\n\n")
         .map(Machine::new)
         .map(|machine| Machine {
                            button_a: machine.button_a,
                            button_b: machine.button_b,
                            prize: (machine.prize.0 + 10000000000000, machine.prize.1 + 10000000000000) })
         .map(|machine| machine.lowest_prize().unwrap_or(0))
         .sum()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        let input =
"Button A: X+94, Y+34
Button B: X+22, Y+67
Prize: X=8400, Y=5400

Button A: X+26, Y+66
Button B: X+67, Y+21
Prize: X=12748, Y=12176

Button A: X+17, Y+86
Button B: X+84, Y+37
Prize: X=7870, Y=6450

Button A: X+69, Y+23
Button B: X+27, Y+71
Prize: X=18641, Y=10279";
        assert_eq!(win_tokens(&input), 480);
    }
}