summaryrefslogtreecommitdiff
path: root/2024_rust/src/bin/day13.rs
blob: 92d70391a7956abc3ab446af64e4ac23a32c4c1c (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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use regex::Regex;

#[derive(Debug)]
struct Machine1 {
    a: (u32, u32),
    b: (u32, u32),
    prize: (u32, u32),
}

impl Machine1 {
    fn parse(input: &str) -> Vec<Self> {
        let mut result: Vec<_> = vec![];
        let re = Regex::new(
            r"Button A: X\+([0-9]+), Y\+([0-9]+)
Button B: X\+([0-9]+), Y\+([0-9]+)
Prize: X=([0-9]+), Y=([0-9]+)",
        )
        .unwrap();
        for (_, [ax, ay, bx, by, x, y]) in re.captures_iter(input).map(|c| c.extract()) {
            result.push(Machine1 {
                a: (ax.parse().unwrap(), ay.parse().unwrap()),
                b: (bx.parse().unwrap(), by.parse().unwrap()),
                prize: (x.parse().unwrap(), y.parse().unwrap()),
            });
        }
        // println!("Result: {result:?}");
        result
    }

    fn solve(&self) -> Option<(u32, u32)> {
        for pushesb in (0..100).rev() {
            for pushesa in 0..100 {
                if self.prize.0 == self.a.0 * pushesa + self.b.0 * pushesb
                    && self.prize.1 == self.a.1 * pushesa + self.b.1 * pushesb
                {
                    // println!("{self:?} solved with {pushesa} {pushesb} pushes!");
                    return Some((pushesa, pushesb));
                }
            }
        }
        None
    }
}

fn p1(input: &str) -> String {
    let result: u32 = Machine1::parse(input)
        .iter()
        .filter_map(Machine1::solve)
        .map(|(nx, ny)| nx * 3 + ny)
        .sum();

    result.to_string()
}

#[derive(Debug)]
struct Machine2 {
    a: (i64, i64),
    b: (i64, i64),
    prize: (i64, i64),
}

fn intdiv(x: i64, y: i64) -> Option<i64> {
    if x % y == 0 {
        Some(x / y)
    } else {
        None
    }
}

impl Machine2 {
    fn parse(input: &str) -> Vec<Self> {
        let mut result: Vec<_> = vec![];
        let re = Regex::new(
            r"Button A: X\+([0-9]+), Y\+([0-9]+)
Button B: X\+([0-9]+), Y\+([0-9]+)
Prize: X=([0-9]+), Y=([0-9]+)",
        )
        .unwrap();
        for (_, [ax, ay, bx, by, x, y]) in re.captures_iter(input).map(|c| c.extract()) {
            result.push(Machine2 {
                a: (ax.parse().unwrap(), ay.parse().unwrap()),
                b: (bx.parse().unwrap(), by.parse().unwrap()),
                prize: (
                    x.parse::<i64>().unwrap() + 10000000000000,
                    y.parse::<i64>().unwrap() + 10000000000000,
                ),
            });
        }
        result
    }

    fn solve(&self) -> Option<(i64, i64)> {
        let pa = intdiv(
            self.prize.0 * self.b.1 - self.prize.1 * self.b.0,
            self.a.0 * self.b.1 - self.a.1 * self.b.0,
        )?;
        let pb = intdiv(self.prize.0 - (pa * self.a.0), self.b.0)?;
        Some((pa, pb))
    }
}

fn p2(input: &str) -> String {
    let result: i64 = Machine2::parse(input)
        .iter()
        .filter_map(Machine2::solve)
        .map(|(nx, ny)| nx * 3 + ny)
        .sum();

    result.to_string()
}

fn main() {
    aoc2024::run_day("13", p1, p2);
}

#[cfg(test)]
mod tests {
    use super::{p1, p2};

    #[test]
    fn day13_p1() {
        assert_eq!(p1(&aoc2024::read_input("13")), "39290");
    }

    #[test]
    fn day13_p2() {
        assert_eq!(p2(&aoc2024::read_input("13")), "73458657399094");
    }
}