diff --git a/Cargo.lock b/Cargo.lock index 393e58d..725723c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,7 @@ version = 3 name = "advent-of-code-2024" version = "0.1.0" dependencies = [ + "good_lp", "regex", "threadpool", ] @@ -19,18 +20,93 @@ dependencies = [ "memchr", ] +[[package]] +name = "bitflags" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" + +[[package]] +name = "coin_cbc" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d602045cd2e7ad02608a71492af94357f493a6f3c934ce854c03bf10fddc5780" +dependencies = [ + "coin_cbc_sys", + "lazy_static", +] + +[[package]] +name = "coin_cbc_sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "085619f8bdc38e24e25c6336ecc3f2e6c0543d67566dff6daef0e32f7ac20f76" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + +[[package]] +name = "good_lp" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97630e1e456d7081c524488a87d8f8f7ed0fd3100ba10c55e3cfa7add5ce05c6" +dependencies = [ + "coin_cbc", + "fnv", + "lpsolve", +] + [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +[[package]] +name = "lpsolve" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516c671a8790d7b5a5c1f2140c36d3619335366fda108db1ca6d8359bd096ecd" +dependencies = [ + "bitflags", + "libc", + "lpsolve-sys", +] + +[[package]] +name = "lpsolve-sys" +version = "5.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0776862d06b54bdea2ed14227f56a2913b39903e06849dce7b805d609ef6a85d" +dependencies = [ + "gcc", + "libc", +] + [[package]] name = "memchr" version = "2.7.4" @@ -47,6 +123,12 @@ dependencies = [ "libc", ] +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + [[package]] name = "regex" version = "1.11.1" diff --git a/Cargo.toml b/Cargo.toml index ab85ac5..ce32e3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +good_lp = {version = "1.10.0", features = ["lpsolve"]} regex = "1.11.1" threadpool = "1.8.1" diff --git a/flake.nix b/flake.nix index 2149150..d421ba8 100644 --- a/flake.nix +++ b/flake.nix @@ -14,7 +14,7 @@ { defaultPackage = naersk-lib.buildPackage ./.; devShell = with pkgs; mkShell { - buildInputs = [ cargo rustc rustfmt pre-commit rustPackages.clippy zip bash ]; + buildInputs = [ cargo rustc rustfmt pre-commit rustPackages.clippy zip bash cbc lp_solve ]; RUST_SRC_PATH = rustPlatform.rustLibSrc; }; } diff --git a/src/bin/d13p1.rs b/src/bin/d13p1.rs new file mode 100644 index 0000000..449b3fa --- /dev/null +++ b/src/bin/d13p1.rs @@ -0,0 +1,89 @@ +use std::collections::{HashMap, HashSet}; + +use advent_of_code_2024::{make_main, next, Pair, SResult}; +use good_lp::{ + coin_cbc, constraint::{self, eq}, variable, variables, Constraint, Expression, ProblemVariables, + Solution, SolverModel, WithMipGap, +}; +use regex::Regex; + +make_main!(); + +fn solve(lines: Vec) -> SResult<(usize, usize)> { + let mut total = 0; + let mut total2 = 0; + let button_regex = + Regex::new(r"^Button (?[^:]+): X\+(?\d+), Y\+(?\d+)$").unwrap(); + let prize_regex = Regex::new(r"^Prize: X=(?\d+), Y=(?\d+)$").unwrap(); + let mut buttons: HashMap = HashMap::default(); + for line in lines { + if line.trim() == "" { + buttons.clear(); + continue; + } + + if let Some(caps) = button_regex.captures(&line) { + let xvel = caps["xvel"].parse::().unwrap(); + let yvel = caps["yvel"].parse::().unwrap(); + buttons.insert(caps["name"].into(), (xvel, yvel)); + } else if let Some(caps) = prize_regex.captures(&line) { + let xpos = caps["xpos"].parse::().unwrap(); + let ypos = caps["ypos"].parse::().unwrap(); + total += solve2(&buttons, (xpos, ypos)); + let ans2 = solve2(&buttons, (xpos + 10000000000000, ypos + 10000000000000)); + if ans2 > 0 { + println!("Solved for pos {}, {}", xpos, ypos); + } + total2 += ans2; + } + } + Ok((total, total2)) +} + +fn solve2(buttons: &HashMap, prize: Pair) -> usize { + let ax = buttons["A"].0 as f64; + let ay = buttons["A"].1 as f64; + let bx = buttons["B"].0 as f64; + let by = buttons["B"].1 as f64; + variables! { + vars2: + 0 <= a (integer) ; + 0 <= b (integer) ; + } + + let sol = match vars2.minimise(a * 3 + b) + .using(coin_cbc) + .with(eq(a*ax+b*bx, prize.0 as f64)) + .with(eq(a*ay+b*by, prize.1 as f64)) + .solve() { + Ok(s) => s, + Err(_) => return 0, + }; + + println!("a {}", sol.value(a)); + println!("b {}", sol.value(b)); + let a = sol.value(a).round() as usize; + let b = sol.value(b).round() as usize; + + + let ax = buttons["A"].0; + let ay = buttons["A"].1; + let bx = buttons["B"].0; + let by = buttons["B"].1; + assert_eq!((a*ax + b*bx, a*ay+b*by), prize); + + a * 3 + b +} + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn lp_solve() { + let strings: Vec = input!("d13p1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (480, 0)); + } +} diff --git a/src/bin/d13p1.txt b/src/bin/d13p1.txt new file mode 100644 index 0000000..444a287 --- /dev/null +++ b/src/bin/d13p1.txt @@ -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 \ No newline at end of file