add: try solving with lp
This commit is contained in:
Generated
+82
@@ -6,6 +6,7 @@ version = 3
|
|||||||
name = "advent-of-code-2024"
|
name = "advent-of-code-2024"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"good_lp",
|
||||||
"regex",
|
"regex",
|
||||||
"threadpool",
|
"threadpool",
|
||||||
]
|
]
|
||||||
@@ -19,18 +20,93 @@ dependencies = [
|
|||||||
"memchr",
|
"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]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.167"
|
version = "0.2.167"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
|
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]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
@@ -47,6 +123,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
|
|||||||
@@ -4,5 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
good_lp = {version = "1.10.0", features = ["lpsolve"]}
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
threadpool = "1.8.1"
|
threadpool = "1.8.1"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
{
|
{
|
||||||
defaultPackage = naersk-lib.buildPackage ./.;
|
defaultPackage = naersk-lib.buildPackage ./.;
|
||||||
devShell = with pkgs; mkShell {
|
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;
|
RUST_SRC_PATH = rustPlatform.rustLibSrc;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user