1
0
Fork 0
This commit is contained in:
Lars Martens 2025-12-10 22:17:18 +01:00
parent 257c7e5cb6
commit 8673603676
Signed by: haselkern
GPG key ID: B5CF1F363C179AD4
3 changed files with 267 additions and 7 deletions

128
Cargo.lock generated
View file

@ -34,9 +34,16 @@ dependencies = [
"cached", "cached",
"glam", "glam",
"itertools", "itertools",
"microlp",
"rayon", "rayon",
] ]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.19.0" version = "3.19.0"
@ -208,6 +215,74 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "log"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "matrixmultiply"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08"
dependencies = [
"autocfg",
"rawpointer",
]
[[package]]
name = "microlp"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d1790c73b93164ff65868f63164497cb32339458a9297e17e212d91df62258"
dependencies = [
"log",
"sprs",
]
[[package]]
name = "ndarray"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7c9125e8f6f10c9da3aad044cc918cf8784fa34de857b1aa68038eb05a50a9"
dependencies = [
"matrixmultiply",
"num-complex",
"num-integer",
"num-traits",
"portable-atomic",
"portable-atomic-util",
"rawpointer",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.20.2" version = "1.20.2"
@ -215,23 +290,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]] [[package]]
name = "proc-macro2" name = "portable-atomic"
version = "1.0.92" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]]
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.37" version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rawpointer"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.11.0" version = "1.11.0"
@ -258,6 +354,24 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "sprs"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dca58a33be2188d4edc71534f8bafa826e787cc28ca1c47f31be3423f0d6e55"
dependencies = [
"ndarray",
"num-complex",
"num-traits",
"smallvec",
]
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@ -266,9 +380,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.89" version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -8,6 +8,7 @@ anyhow = "1.0.100"
cached = "0.56.0" cached = "0.56.0"
glam = "0.30.9" glam = "0.30.9"
itertools = "0.14.0" itertools = "0.14.0"
microlp = "0.2.11"
rayon = "1.11.0" rayon = "1.11.0"
[profile.release] [profile.release]

145
src/bin/10.rs Normal file
View file

@ -0,0 +1,145 @@
use aoc::*;
use microlp::{ComparisonOp, OptimizationDirection, Problem};
use std::collections::VecDeque;
const INPUT: &str = include_str!("../../input/10");
fn main() {
println!("Part 1: {}", part1(INPUT));
println!("Part 2: {}", part2(INPUT));
}
#[test]
fn example() {
assert_example!(part1, "10-test", 7);
assert_example!(part2, "10-test", 33);
}
fn part1(input: &str) -> usize {
parse_input(input).iter().map(minimum_light_presses).sum()
}
fn part2(input: &str) -> usize {
parse_input(input).iter().map(minimum_joltage_presses).sum()
}
#[derive(Default, Debug)]
struct Machine {
required_lights: Vec<bool>,
buttons: Vec<Button>,
required_joltages: Vec<usize>,
}
impl Machine {
fn parse(input: &str) -> Self {
let mut m = Machine::default();
for part in input.split_whitespace() {
if part.starts_with('[') {
m.required_lights = parse_lights(part);
} else if part.starts_with('(') {
m.buttons.push(parse_button(part));
} else if part.starts_with('{') {
m.required_joltages = parse_joltages(part);
} else {
panic!("Unknown part '{}'", part);
}
}
m
}
}
fn minimum_light_presses(machine: &Machine) -> usize {
let mut work = VecDeque::new();
work.push_back((vec![false; machine.required_lights.len()], 0usize));
while let Some((lights, presses)) = work.pop_front() {
let matches = lights.iter().eq(&machine.required_lights);
if matches {
return presses;
}
let new_lights = machine
.buttons
.iter()
.map(|b| (press_light(&lights, b), presses + 1));
work.extend(new_lights);
}
unreachable!()
}
fn minimum_joltage_presses(machine: &Machine) -> usize {
let mut problem = Problem::new(OptimizationDirection::Minimize);
let mut buttons_vars = Vec::new();
for _ in 0..machine.buttons.len() {
let var = problem.add_integer_var(1.0, (0, i32::MAX));
buttons_vars.push(var);
}
for (i, joltage) in machine.required_joltages.iter().copied().enumerate() {
let vars = buttons_vars
.iter()
.copied()
.zip(&machine.buttons)
.filter(|(_var, button)| button.contains(&i))
.map(|(var, _button)| (var, 1.0));
problem.add_constraint(vars, ComparisonOp::Eq, joltage as f64);
}
let solution = problem.solve().unwrap();
buttons_vars
.into_iter()
.map(|var| solution[var].round() as usize)
.sum()
}
fn press_light(lights: &[bool], button: &Button) -> Vec<bool> {
let mut lights = lights.to_vec();
for &b in button {
lights[b] ^= true;
}
lights
}
fn parse_lights(input: &str) -> Vec<bool> {
input
.strip_prefix('[')
.unwrap()
.strip_suffix(']')
.unwrap()
.chars()
.map(|c| match c {
'.' => false,
'#' => true,
other => panic!("unknown light char '{other}'"),
})
.collect()
}
type Button = Vec<usize>;
fn parse_button(input: &str) -> Button {
input
.strip_prefix('(')
.unwrap()
.strip_suffix(')')
.unwrap()
.split(',')
.map(|c| c.parse().unwrap())
.collect()
}
fn parse_joltages(input: &str) -> Vec<usize> {
input
.strip_prefix('{')
.unwrap()
.strip_suffix('}')
.unwrap()
.split(',')
.map(|c| c.parse().unwrap())
.collect()
}
fn parse_input(input: &str) -> Vec<Machine> {
input.lines().map(Machine::parse).collect()
}