DEVELOPMENT ENVIRONMENT

~liljamo/aoc2024

98f77e7ed7c9592aa066ce4a614b17dc9e1ddf18 — Jonni Liljamo a month ago 8f7092f
feat: day13
5 files changed, 225 insertions(+), 0 deletions(-)

A input/day13/example
A src/day13/mod.rs
A src/day13/part1.rs
A src/day13/part2.rs
M src/main.rs
A input/day13/example => input/day13/example +15 -0
@@ 0,0 1,15 @@
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

A src/day13/mod.rs => src/day13/mod.rs +11 -0
@@ 0,0 1,11 @@
use std::path::Path;

mod part1;
mod part2;

pub fn solve(input: &Path) -> anyhow::Result<()> {
    println!("part one: {}", part1::part_one(input)?);
    println!("part two: {}", part2::part_two(input)?);

    Ok(())
}

A src/day13/part1.rs => src/day13/part1.rs +97 -0
@@ 0,0 1,97 @@
use std::{
    fs::File,
    io::{BufRead, BufReader},
    path::Path,
};

#[derive(Debug)]
struct M {
    a: P,
    b: P,
    p: P,
}

impl M {
    fn from_lines(lines: &[String]) -> Self {
        let a_line = &lines[0];
        let b_line = &lines[1];
        let p_line = &lines[2];

        Self {
            a: P {
                x: a_line[&a_line.find("X").unwrap() + 2..a_line.find(",").unwrap()]
                    .parse()
                    .unwrap(),
                y: a_line[&a_line.find("Y").unwrap() + 2..a_line.len()]
                    .parse()
                    .unwrap(),
            },
            b: P {
                x: b_line[&b_line.find("X").unwrap() + 2..b_line.find(",").unwrap()]
                    .parse()
                    .unwrap(),
                y: b_line[&b_line.find("Y").unwrap() + 2..b_line.len()]
                    .parse()
                    .unwrap(),
            },
            p: P {
                x: p_line[&p_line.find("X").unwrap() + 2..p_line.find(",").unwrap()]
                    .parse()
                    .unwrap(),
                y: p_line[&p_line.find("Y").unwrap() + 2..p_line.len()]
                    .parse()
                    .unwrap(),
            },
        }
    }
}

#[derive(Debug)]
struct P {
    x: usize,
    y: usize,
}

pub fn part_one(input: &Path) -> anyhow::Result<usize> {
    let reader = BufReader::new(File::open(input)?);

    let machines: Vec<M> = reader
        .lines()
        .filter_map(|l| {
            let l = l.unwrap();
            if !l.is_empty() {
                Some(l)
            } else {
                None
            }
        })
        .collect::<Vec<String>>()
        .chunks(3)
        .map(|l| -> M { M::from_lines(l) })
        .collect();

    let mut answer = 0;
    for machine in machines {
        let mut oks: Vec<usize> = vec![];
        let (mut x, mut y) = (0, 0);
        'a: for a in 1..101 {
            x += machine.a.x;
            y += machine.a.y;
            let (mut x, mut y) = (x, y);
            for b in 1..101 {
                x += machine.b.x;
                y += machine.b.y;
                if x == machine.p.x && y == machine.p.y {
                    oks.push(a * 3 + b);
                    continue 'a;
                }
            }
        }
        if !oks.is_empty() {
            oks.sort();
            answer += oks.first().unwrap();
        }
    }

    Ok(answer)
}

A src/day13/part2.rs => src/day13/part2.rs +94 -0
@@ 0,0 1,94 @@
use std::{
    fs::File,
    io::{BufRead, BufReader},
    path::Path,
};

#[derive(Debug)]
struct M {
    a: P,
    b: P,
    p: P,
}

impl M {
    fn from_lines(lines: &[String]) -> Self {
        let a_line = &lines[0];
        let b_line = &lines[1];
        let p_line = &lines[2];

        Self {
            a: P {
                x: a_line[&a_line.find("X").unwrap() + 2..a_line.find(",").unwrap()]
                    .parse()
                    .unwrap(),
                y: a_line[&a_line.find("Y").unwrap() + 2..a_line.len()]
                    .parse()
                    .unwrap(),
            },
            b: P {
                x: b_line[&b_line.find("X").unwrap() + 2..b_line.find(",").unwrap()]
                    .parse()
                    .unwrap(),
                y: b_line[&b_line.find("Y").unwrap() + 2..b_line.len()]
                    .parse()
                    .unwrap(),
            },
            p: P {
                x: p_line[&p_line.find("X").unwrap() + 2..p_line.find(",").unwrap()]
                    .parse::<usize>()
                    .unwrap()
                    + 10000000000000,
                y: p_line[&p_line.find("Y").unwrap() + 2..p_line.len()]
                    .parse::<usize>()
                    .unwrap()
                    + 10000000000000,
            },
        }
    }
}

#[derive(Debug)]
struct P {
    x: usize,
    y: usize,
}

pub fn part_two(input: &Path) -> anyhow::Result<usize> {
    let reader = BufReader::new(File::open(input)?);

    let machines: Vec<M> = reader
        .lines()
        .filter_map(|l| {
            let l = l.unwrap();
            if !l.is_empty() {
                Some(l)
            } else {
                None
            }
        })
        .collect::<Vec<String>>()
        .chunks(3)
        .map(|l| -> M { M::from_lines(l) })
        .collect();

    let mut answer = 0;
    for m in machines {
        println!();
        println!("{}x + {}y = {}", m.a.x, m.b.x, m.p.x);
        println!("{}x + {}y = {}", m.a.y, m.b.y, m.p.y);
        println!();

        let b: i64 = (m.p.y as i64 * m.a.x as i64 - m.p.x as i64 * m.a.y as i64)
            / (m.b.y as i64 * m.a.x as i64 - m.b.x as i64 * m.a.y as i64);
        let a: i64 = (m.p.x as i64 - b * m.b.x as i64) / m.a.x as i64;
        if m.a.x as i64 * a + m.b.x as i64 * b == m.p.x as i64
            && m.a.y as i64 * a + m.b.y as i64 * b == m.p.y as i64
        {
            answer += a * 3 + b;
            println!("yes");
        }
    }

    Ok(answer as usize)
}

M src/main.rs => src/main.rs +8 -0
@@ 6,6 6,7 @@ mod day1;
mod day10;
mod day11;
mod day12;
mod day13;
mod day2;
mod day3;
mod day4;


@@ 71,6 72,10 @@ enum DayArgs {
        #[arg(short)]
        input: PathBuf,
    },
    Day13 {
        #[arg(short)]
        input: PathBuf,
    },
}

fn main() -> anyhow::Result<()> {


@@ 113,6 118,9 @@ fn main() -> anyhow::Result<()> {
        DayArgs::Day12 { input } => {
            day12::solve(&input)?;
        }
        DayArgs::Day13 { input } => {
            day13::solve(&input)?;
        }
    }

    Ok(())