mirror of
https://github.com/Noratrieb/advent-of-code.git
synced 2026-01-14 09:35:01 +01:00
opts
This commit is contained in:
parent
93af372574
commit
b12e92a5cb
8 changed files with 238 additions and 10 deletions
|
|
@ -9,6 +9,8 @@ edition = "2021"
|
|||
nom.workspace = true
|
||||
helper.workspace = true
|
||||
divan.workspace = true
|
||||
arrayvec = "0.7.4"
|
||||
bstr = "1.8.0"
|
||||
|
||||
[[bench]]
|
||||
name = "benches"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
mod p2ascii;
|
||||
mod p2cache;
|
||||
mod p2chunks;
|
||||
mod p2no_alloc;
|
||||
|
||||
use helper::{Day, Variants};
|
||||
|
||||
|
|
@ -11,11 +14,14 @@ struct Day04;
|
|||
helper::define_variants! {
|
||||
day => crate::Day04;
|
||||
part1 {
|
||||
basic => crate::part1, sample_count=1000;
|
||||
basic => crate::part1;
|
||||
}
|
||||
part2 {
|
||||
basic => crate::part2, sample_count=100;
|
||||
cache => crate::p2cache::part2, sample_count=1000;
|
||||
cache => crate::p2cache::part2;
|
||||
no_alloc => crate::p2no_alloc::part2;
|
||||
ascii => crate::p2ascii::part2;
|
||||
chunks => crate::p2chunks::part2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
43
2023/day04/src/p2ascii.rs
Normal file
43
2023/day04/src/p2ascii.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
fn line_match_count(line: &str) -> usize {
|
||||
let mut numbers = line.split(':').nth(1).unwrap().split("|");
|
||||
let winning = numbers
|
||||
.next()
|
||||
.unwrap()
|
||||
.split_ascii_whitespace()
|
||||
.collect::<arrayvec::ArrayVec<_, 16>>();
|
||||
|
||||
let you_have = numbers.next().unwrap().split_ascii_whitespace();
|
||||
|
||||
you_have
|
||||
.filter(|have| winning.iter().any(|w| w == have))
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn part2(input: &str) -> u64 {
|
||||
let lines = input.lines().map(line_match_count).collect::<Vec<_>>();
|
||||
|
||||
let mut cache = vec![0; lines.len()];
|
||||
|
||||
let mut processed = 0;
|
||||
|
||||
// By iterating backwards, we ensure the cache is always populated for every subsequent line.
|
||||
for (i, result) in lines.iter().copied().enumerate().rev() {
|
||||
let before = processed;
|
||||
processed += 1; // Every card gives us one card.
|
||||
// Now, let's see how many cards this card will expand to.
|
||||
for expand in (i + 1)..((i + 1) + result) {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!(
|
||||
"{} expands to {} which is worth {}",
|
||||
i + 1,
|
||||
expand + 1,
|
||||
cache[expand]
|
||||
);
|
||||
// Since the value is bigger than i, it must be cached!
|
||||
processed += cache[expand];
|
||||
}
|
||||
cache[i] = processed - before;
|
||||
}
|
||||
|
||||
processed
|
||||
}
|
||||
49
2023/day04/src/p2chunks.rs
Normal file
49
2023/day04/src/p2chunks.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
fn line_match_count(line: &str) -> usize {
|
||||
let mut numbers = line.split(':').nth(1).unwrap().split("|");
|
||||
let winning = numbers
|
||||
.next()
|
||||
.unwrap()
|
||||
.as_bytes()
|
||||
// Chunks of double digit numbers with a leading space. We don't care about the trailing space.
|
||||
.chunks_exact(3)
|
||||
.collect::<arrayvec::ArrayVec<_, 16>>();
|
||||
|
||||
let you_have = numbers.next().unwrap().as_bytes().chunks_exact(3);
|
||||
|
||||
you_have
|
||||
.filter(|have| {
|
||||
winning.iter().any(|w| {
|
||||
w == have
|
||||
})
|
||||
})
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn part2(input: &str) -> u64 {
|
||||
let lines = input.lines().map(line_match_count).collect::<Vec<_>>();
|
||||
|
||||
let mut cache = vec![0; lines.len()];
|
||||
|
||||
let mut processed = 0;
|
||||
|
||||
// By iterating backwards, we ensure the cache is always populated for every subsequent line.
|
||||
for (i, result) in lines.iter().copied().enumerate().rev() {
|
||||
let before = processed;
|
||||
processed += 1; // Every card gives us one card.
|
||||
// Now, let's see how many cards this card will expand to.
|
||||
for expand in (i + 1)..((i + 1) + result) {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!(
|
||||
"{} expands to {} which is worth {}",
|
||||
i + 1,
|
||||
expand + 1,
|
||||
cache[expand]
|
||||
);
|
||||
// Since the value is bigger than i, it must be cached!
|
||||
processed += cache[expand];
|
||||
}
|
||||
cache[i] = processed - before;
|
||||
}
|
||||
|
||||
processed
|
||||
}
|
||||
43
2023/day04/src/p2no_alloc.rs
Normal file
43
2023/day04/src/p2no_alloc.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
fn line_match_count(line: &str) -> usize {
|
||||
let mut numbers = line.split(':').nth(1).unwrap().split("|");
|
||||
let winning = numbers
|
||||
.next()
|
||||
.unwrap()
|
||||
.split_whitespace()
|
||||
.collect::<arrayvec::ArrayVec<_, 16>>();
|
||||
|
||||
let you_have = numbers.next().unwrap().split_whitespace();
|
||||
|
||||
you_have
|
||||
.filter(|have| winning.iter().any(|w| w == have))
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn part2(input: &str) -> u64 {
|
||||
let lines = input.lines().map(line_match_count).collect::<Vec<_>>();
|
||||
|
||||
let mut cache = vec![0; lines.len()];
|
||||
|
||||
let mut processed = 0;
|
||||
|
||||
// By iterating backwards, we ensure the cache is always populated for every subsequent line.
|
||||
for (i, result) in lines.iter().copied().enumerate().rev() {
|
||||
let before = processed;
|
||||
processed += 1; // Every card gives us one card.
|
||||
// Now, let's see how many cards this card will expand to.
|
||||
for expand in (i + 1)..((i + 1) + result) {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!(
|
||||
"{} expands to {} which is worth {}",
|
||||
i + 1,
|
||||
expand + 1,
|
||||
cache[expand]
|
||||
);
|
||||
// Since the value is bigger than i, it must be cached!
|
||||
processed += cache[expand];
|
||||
}
|
||||
cache[i] = processed - before;
|
||||
}
|
||||
|
||||
processed
|
||||
}
|
||||
45
Cargo.lock
generated
45
Cargo.lock
generated
|
|
@ -50,12 +50,29 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.10"
|
||||
|
|
@ -137,6 +154,8 @@ dependencies = [
|
|||
name = "day04"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bstr",
|
||||
"divan",
|
||||
"helper",
|
||||
"nom",
|
||||
|
|
@ -236,6 +255,12 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
|
||||
[[package]]
|
||||
name = "regex-lite"
|
||||
version = "0.1.5"
|
||||
|
|
@ -261,6 +286,26 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.2"
|
||||
|
|
|
|||
45
helper/src/ext.rs
Normal file
45
helper/src/ext.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
use std::mem::MaybeUninit;
|
||||
|
||||
use nom::{character::complete::digit1, combinator::map, IResult};
|
||||
|
||||
pub fn integer(input: &str) -> IResult<&str, u64> {
|
||||
map(digit1, |d: &str| d.parse::<u64>().unwrap())(input)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CollectArrayError;
|
||||
|
||||
/// i will not use itertools i will not use itertools i will not use itertools i will not use itertools
|
||||
pub trait IteratorExt: Iterator {
|
||||
/// Collect an iterator into an array.
|
||||
/// If `next` panics, collected items are leaked. Too bad!
|
||||
fn collect_array<const N: usize>(&mut self) -> Result<[Self::Item; N], CollectArrayError> {
|
||||
// SAFETY: Uninit is valid for MaybeUninit
|
||||
let mut array: [MaybeUninit<Self::Item>; N] = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
|
||||
for i in 0..array.len() {
|
||||
array[i].write(self.next().ok_or(CollectArrayError)?);
|
||||
}
|
||||
|
||||
if self.next().is_some() {
|
||||
return Err(CollectArrayError);
|
||||
}
|
||||
|
||||
// SAFETY: All elements have been initialized
|
||||
Ok(array.map(|elem| unsafe { elem.assume_init() }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator> IteratorExt for I {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::IteratorExt;
|
||||
|
||||
#[test]
|
||||
fn collect_array() {
|
||||
assert!([0, 1].into_iter().collect_array::<3>().is_err());
|
||||
assert!([0, 1].into_iter().collect_array::<1>().is_err());
|
||||
assert_eq!([0, 1].into_iter().collect_array().unwrap(), [0, 1]);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
mod cmd;
|
||||
mod ext;
|
||||
|
||||
use std::{borrow::Cow, fmt::Debug};
|
||||
|
||||
use nom::{character::complete::digit1, combinator::map, IResult};
|
||||
|
||||
pub use self::cmd::main;
|
||||
pub use divan;
|
||||
pub use self::ext::*;
|
||||
|
||||
pub type Solution = fn(&str) -> u64;
|
||||
|
||||
|
|
@ -123,7 +122,7 @@ macro_rules! benchmarks {
|
|||
#[macro_export]
|
||||
macro_rules! _bench_sample_count {
|
||||
(;$($tt:tt)*) => {
|
||||
#[::divan::bench(sample_count = 10_000)]
|
||||
#[::divan::bench(sample_count = 5000)]
|
||||
$($tt)*
|
||||
};
|
||||
($sample_count:expr; $($tt:tt)*) => {
|
||||
|
|
@ -209,7 +208,3 @@ macro_rules! tests {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn integer(input: &str) -> IResult<&str, u64> {
|
||||
map(digit1, |d: &str| d.parse::<u64>().unwrap())(input)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue