day7: parallel solution, < 100ms
This is definitely a problem that calls for DFS, but I couldn't be bothered.
This commit is contained in:
parent
868c3e56fc
commit
3e0bc0d5cc
69
7/Cargo.lock
generated
69
7/Cargo.lock
generated
@ -2,11 +2,44 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "day7"
|
name = "day7"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"rayon",
|
||||||
|
"thread_local",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -23,3 +56,39 @@ checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.20.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
@ -5,3 +5,5 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
|
rayon = "1.10.0"
|
||||||
|
thread_local = "1.1.8"
|
||||||
|
103
7/src/main.rs
103
7/src/main.rs
@ -3,6 +3,8 @@ use std::io::{BufRead, BufReader, Lines};
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||||
|
use thread_local::ThreadLocal;
|
||||||
|
|
||||||
// BOILERPLATE
|
// BOILERPLATE
|
||||||
type InputIter = Lines<BufReader<File>>;
|
type InputIter = Lines<BufReader<File>>;
|
||||||
@ -36,7 +38,7 @@ fn main() {
|
|||||||
println!("Total duration: {}", duration_format(duration1 + duration2));
|
println!("Total duration: {}", duration_format(duration1 + duration2));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
struct Calibration {
|
struct Calibration {
|
||||||
result: u64,
|
result: u64,
|
||||||
numbers: Vec<u64>,
|
numbers: Vec<u64>,
|
||||||
@ -55,9 +57,10 @@ impl From<&str> for Calibration {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Calibrations {
|
struct Calibrations {
|
||||||
cals: Vec<Calibration>,
|
cals: Vec<Calibration>,
|
||||||
|
longest_cal: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
enum Operator {
|
enum Operator {
|
||||||
Add,
|
Add,
|
||||||
Multiply,
|
Multiply,
|
||||||
@ -69,7 +72,7 @@ impl Operator {
|
|||||||
match self {
|
match self {
|
||||||
Operator::Add => a + b,
|
Operator::Add => a + b,
|
||||||
Operator::Multiply => a * b,
|
Operator::Multiply => a * b,
|
||||||
Operator::Concatenate => u64::pow(10, b.to_string().len() as u32) * a + b,
|
Operator::Concatenate => u64::pow(10, u64::ilog10(b) + 1) * a + b,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,10 +80,55 @@ impl Operator {
|
|||||||
impl<T: BufRead> From<Lines<T>> for Calibrations {
|
impl<T: BufRead> From<Lines<T>> for Calibrations {
|
||||||
fn from(input: Lines<T>) -> Self {
|
fn from(input: Lines<T>) -> Self {
|
||||||
let mut cals = Vec::new();
|
let mut cals = Vec::new();
|
||||||
|
let mut longest_cal = 0;
|
||||||
for line in input.map(|l| l.unwrap()) {
|
for line in input.map(|l| l.unwrap()) {
|
||||||
cals.push(line.as_str().into());
|
let cal: Calibration = line.as_str().into();
|
||||||
|
longest_cal = std::cmp::max(longest_cal, cal.numbers.len());
|
||||||
|
cals.push(cal);
|
||||||
}
|
}
|
||||||
Self { cals }
|
Self { cals, longest_cal }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Calibrations {
|
||||||
|
fn make_operator_sets(operators: &[Operator], n_opers: usize) -> Vec<Vec<Vec<Operator>>> {
|
||||||
|
(0..n_opers)
|
||||||
|
.map(|k| {
|
||||||
|
std::iter::repeat_n(operators.iter().map(|v| *v), k)
|
||||||
|
.multi_cartesian_product()
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
fn check_oper_set(cal: &Calibration, oper_set: &Vec<Operator>) -> bool {
|
||||||
|
let accum = oper_set
|
||||||
|
.iter()
|
||||||
|
.zip(cal.numbers.iter().skip(1))
|
||||||
|
.fold(cal.numbers[0], |accum, (oper, val)| oper.exec(accum, *val));
|
||||||
|
if accum == cal.result {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn possible(&self, operators: &[Operator]) -> u64 {
|
||||||
|
let operator_sets = Calibrations::make_operator_sets(operators, self.longest_cal);
|
||||||
|
self.cals
|
||||||
|
.par_iter()
|
||||||
|
.map(|cal| {
|
||||||
|
let n_opers = cal.numbers.len() - 1;
|
||||||
|
let tl = ThreadLocal::new();
|
||||||
|
if operator_sets[n_opers]
|
||||||
|
.par_iter()
|
||||||
|
.find_any(|oper_set| Self::check_oper_set(&cal, &oper_set))
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
let cal_local = tl.get_or(|| cal.clone());
|
||||||
|
return cal_local.result;
|
||||||
|
}
|
||||||
|
0
|
||||||
|
})
|
||||||
|
.sum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,56 +136,15 @@ impl<T: BufRead> From<Lines<T>> for Calibrations {
|
|||||||
|
|
||||||
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
let cals = Calibrations::from(input);
|
let cals = Calibrations::from(input);
|
||||||
// println!("{:?}", cals);
|
|
||||||
let mut sum = 0;
|
|
||||||
|
|
||||||
let operators = [Operator::Add, Operator::Multiply];
|
let operators = [Operator::Add, Operator::Multiply];
|
||||||
|
cals.possible(&operators)
|
||||||
for cal in &cals.cals {
|
|
||||||
let n_opers = cal.numbers.len() - 1;
|
|
||||||
// println!("CAL: {:?} (opers: {})", cal, n_opers);
|
|
||||||
for oper_set in std::iter::repeat_n(operators.iter(), n_opers).multi_cartesian_product() {
|
|
||||||
// println!("operator set: {:?}", oper_set);
|
|
||||||
let mut accum = cal.numbers[0];
|
|
||||||
for (i, oper) in oper_set.iter().enumerate() {
|
|
||||||
// println!("Testing {} {:?} {}", accum, oper, cal.numbers[i+1]);
|
|
||||||
accum = oper.exec(accum, cal.numbers[i + 1]);
|
|
||||||
}
|
|
||||||
if accum == cal.result {
|
|
||||||
sum += cal.result;
|
|
||||||
// println!("Matched!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// println!("NO MATCHES");
|
|
||||||
}
|
|
||||||
sum
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PROBLEM 2 solution
|
// PROBLEM 2 solution
|
||||||
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
let cals = Calibrations::from(input);
|
let cals = Calibrations::from(input);
|
||||||
let mut sum = 0;
|
|
||||||
let operators = [Operator::Add, Operator::Multiply, Operator::Concatenate];
|
let operators = [Operator::Add, Operator::Multiply, Operator::Concatenate];
|
||||||
for cal in &cals.cals {
|
cals.possible(&operators)
|
||||||
let n_opers = cal.numbers.len() - 1;
|
|
||||||
// println!("CAL: {:?} (opers: {})", cal, n_opers);
|
|
||||||
for oper_set in std::iter::repeat_n(operators.iter(), n_opers).multi_cartesian_product() {
|
|
||||||
// println!("operator set: {:?}", oper_set);
|
|
||||||
let mut accum = cal.numbers[0];
|
|
||||||
for (i, oper) in oper_set.iter().enumerate() {
|
|
||||||
// println!("Testing {} {:?} {}", accum, oper, cal.numbers[i+1]);
|
|
||||||
accum = oper.exec(accum, cal.numbers[i + 1]);
|
|
||||||
}
|
|
||||||
if accum == cal.result {
|
|
||||||
sum += cal.result;
|
|
||||||
// println!("Matched!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// println!("NO MATCHES");
|
|
||||||
}
|
|
||||||
sum
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user