🏡 index : ~doyle/aoc.git

author Jordan Doyle <jordan@doyle.la> 2024-12-25 14:18:40.0 +07:00:00
committer Jordan Doyle <jordan@doyle.la> 2024-12-25 14:18:40.0 +07:00:00
commit
4ccdd4610da674e68002eb95f21891cd3dea9e62 [patch]
tree
b65467bf3dc28b18f9cfba41d3de98f1a1e7054a
parent
d837d1cc265e5cea16b43376ee5ced6b98b168fb
download
4ccdd4610da674e68002eb95f21891cd3dea9e62.tar.gz

Add 2024 day 13



Diff

 Cargo.lock |  9 ++++++++-
 Cargo.toml |  5 +++++
 README     |  4 ++--
 2024/13.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 113 insertions(+), 3 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index fbe92ee..174e56a 100644
--- a/Cargo.lock
+++ a/Cargo.lock
@@ -1,11 +1,18 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4

[[package]]
name = "anyhow"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"

[[package]]
name = "aoc2023"
version = "0.1.0"
dependencies = [
 "anyhow",
 "arrayvec",
 "itertools",
 "nom",
diff --git a/Cargo.toml b/Cargo.toml
index 254d04e..2867d65 100644
--- a/Cargo.toml
+++ a/Cargo.toml
@@ -1,9 +1,10 @@
[package]
name = "aoc2023"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1"
arrayvec = "0.7"
rangemap = "1.4"
strum = { version = "0.25", features = ["derive"] }
@@ -41,6 +42,10 @@
[[bin]]
name = "aoc2024-08"
path = "2024/08.rs"

[[bin]]
name = "aoc2024-13"
path = "2024/13.rs"

[profile.release]
overflow-checks = true
diff --git a/README b/README
index 68097cf..8f51829 100644
--- a/README
+++ a/README
@@ -26,8 +26,8 @@
|       10 | OCaml    | |       10 | Haskell  |
|       11 | OCaml    | |       11 | Haskell  |
|       12 | OCaml    | |       12 | Rust     |
+---------------------+ |       13 | Haskell  |
                        |       14 | Haskell  |
|       13 | Rust     | |       13 | Haskell  |
+---------------------+ |       14 | Haskell  |
                        |       15 | Haskell  |
                        |       16 | Haskell  |
                        |       17 | Rust     |
diff --git a/2024/13.rs b/2024/13.rs
new file mode 100755
index 0000000..57d472d 100755
--- /dev/null
+++ a/2024/13.rs
@@ -1,0 +1,98 @@
use std::io::Read;

use nom::{
    bytes::complete::tag,
    character::complete::{alpha1, digit1},
    combinator::map_parser,
    multi::separated_list1,
    sequence::{preceded, terminated},
    IResult,
};

fn main() -> Result<(), anyhow::Error> {
    let mut input = String::new();
    std::io::stdin().read_to_string(&mut input)?;

    let (rest, input) = parse_input(&input).unwrap();
    assert!(rest.is_empty());

    part1(&input);
    part2(&input);

    Ok(())
}

fn solve(input: &Input) -> i64 {
    let b = (input.prize.y * input.buttons[0].x - input.prize.x * input.buttons[0].y)
        / (input.buttons[1].y * input.buttons[0].x - input.buttons[1].x * input.buttons[0].y);
    let a = (input.prize.x - b * input.buttons[1].x) / input.buttons[0].x;

    if input.buttons[0].x * a + input.buttons[1].x * b == input.prize.x
        && input.buttons[0].y * a + input.buttons[1].y * b == input.prize.y
    {
        3 * a + b
    } else {
        0
    }
}

fn part1(input: &[Input]) {
    eprintln!("{}", input.iter().map(solve).sum::<i64>());
}

fn part2(input: &[Input]) {
    eprintln!(
        "{}",
        input
            .iter()
            .cloned()
            .map(|v| Input {
                prize: Coords {
                    x: v.prize.x + 10_000_000_000_000,
                    y: v.prize.y + 10_000_000_000_000,
                },
                ..v
            })
            .map(|v| solve(&v))
            .sum::<i64>()
    );
}

#[derive(Debug, Copy, Clone)]
pub struct Coords {
    x: i64,
    y: i64,
}

#[derive(Debug, Clone)]
pub struct Input {
    buttons: Vec<Coords>,
    prize: Coords,
}

fn parse_i64(s: &str) -> IResult<&str, i64> {
    map_parser(digit1, nom::character::complete::i64)(s)
}

fn parse_button(s: &str) -> IResult<&str, Coords> {
    let (s, _b) = preceded(tag("Button "), alpha1)(s)?;
    let (s, x) = preceded(tag(": X+"), parse_i64)(s)?;
    let (s, y) = preceded(tag(", Y+"), parse_i64)(s)?;
    Ok((s, Coords { x, y }))
}

fn parse_prize(s: &str) -> IResult<&str, Coords> {
    let (s, x) = preceded(tag("Prize: X="), parse_i64)(s)?;
    let (s, y) = preceded(tag(", Y="), parse_i64)(s)?;
    Ok((s, Coords { x, y }))
}

fn parse_block(s: &str) -> IResult<&str, Input> {
    let (s, buttons) = terminated(separated_list1(tag("\n"), parse_button), tag("\n"))(s)?;
    let (s, prize) = terminated(parse_prize, tag("\n"))(s)?;
    Ok((s, Input { buttons, prize }))
}

fn parse_input<'a>(s: &'a str) -> IResult<&'a str, Vec<Input>> {
    separated_list1(tag("\n"), parse_block)(s)
}