add: try solving with lp

This commit is contained in:
Charles
2024-12-12 22:49:11 -08:00
parent bdac76d111
commit 3b5da4379c
5 changed files with 188 additions and 1 deletions
Generated
+82
View File
@@ -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"
+1
View File
@@ -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"
+1 -1
View File
@@ -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;
};
}
+89
View File
@@ -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<String>) -> SResult<(usize, usize)> {
let mut total = 0;
let mut total2 = 0;
let button_regex =
Regex::new(r"^Button (?<name>[^:]+): X\+(?<xvel>\d+), Y\+(?<yvel>\d+)$").unwrap();
let prize_regex = Regex::new(r"^Prize: X=(?<xpos>\d+), Y=(?<ypos>\d+)$").unwrap();
let mut buttons: HashMap<String, Pair> = 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::<usize>().unwrap();
let yvel = caps["yvel"].parse::<usize>().unwrap();
buttons.insert(caps["name"].into(), (xvel, yvel));
} else if let Some(caps) = prize_regex.captures(&line) {
let xpos = caps["xpos"].parse::<usize>().unwrap();
let ypos = caps["ypos"].parse::<usize>().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<String, Pair>, 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<String> = input!("d13p1.txt");
let got = solve(strings).unwrap();
assert_eq!(got, (480, 0));
}
}
+15
View File
@@ -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