Untitled

 avatar
unknown
rust
2 months ago
2.6 kB
25
Indexable
pub fn solution(test: bool) -> ((usize, Duration), (usize, Duration)) {
    let lines;
    if test {
        lines = include_str!("../../../AdventOfCodeInputs/problem_inputs_2024/day_13_test.txt");
    } else {
        lines = include_str!("../../../AdventOfCodeInputs/problem_inputs_2024/day_13.txt");
    }
    (solve(&lines, false), solve(&lines, true))
}

fn solve(lines: &str, p2: bool) -> (usize, Duration) {
    let now = Instant::now();
    let claw_machines = lines
        .split("\n\n")
        .map(|x| ClawMachine::from_str(x))
        .collect_vec();
    let mut tokens = 0;
    for (i, machine) in claw_machines.iter().enumerate() {
        let mut machine = *machine;
        if p2 {
            machine.target = machine.target + OFFSET;
        }
        if let Some(ans) = machine.solve() {
            tokens += 3 * ans[(0, 0)].round() as isize + ans[(1, 0)].round() as isize;
        }
    }
    let ans = 0;

    (tokens as usize, now.elapsed())
}

#[derive(Debug, Clone, Copy)]
struct ClawMachine {
    buttons: Matrix2<f64>,
    target: Matrix2x1<f64>,
}

impl ClawMachine {
    fn from_str(lines: &str) -> Self {
        let mut lines = lines.lines();
        let buttom_a_str = lines.next().unwrap().split(':').nth(1).unwrap();
        let buttom_b_str = lines.next().unwrap().split(':').nth(1).unwrap();
        let target_str = lines.next().unwrap().split(':').nth(1).unwrap();
        let button_a = parse_button(buttom_a_str);
        let button_b = parse_button(buttom_b_str);
        let target = parse_button(target_str);
        let target = Matrix2x1::new(target.0 as f64, target.1 as f64);

        let buttons = Matrix2::new(
            button_a.0 as f64,
            button_a.1 as f64,
            button_b.0 as f64,
            button_b.1 as f64,
        )
        .transpose();

        ClawMachine { buttons, target }
    }

    fn solve(&self) -> Option<Matrix2x1<f64>> {
        let inv = self.buttons.try_inverse().unwrap();
        let ans = inv * self.target;
        if check_fraction(ans[(0, 0)]) && check_fraction(ans[(1, 0)]) {
            Some(ans)
        } else {
            None
        }
    }
}

fn parse_button(line: &str) -> (isize, isize) {
    line.split(',')
        .map(|x| {
            x.trim()
                .chars()
                .skip(2)
                .collect::<String>()
                .parse()
                .unwrap()
        })
        .collect_tuple()
        .unwrap()
}

fn check_fraction(num: f64) -> bool {
    (num as isize as f64 - num).abs() < ACC || (num as isize as f64 - num).abs() > (1.0 - ACC)
}
Leave a Comment