From 4fcd930a3203001e3c8a0cb8b4a7e506d189c9ee Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 4 Dec 2023 21:35:48 +0100 Subject: [PATCH] more opts --- 2023/day04/src/lib.rs | 2 ++ 2023/day04/src/p2chunks.rs | 17 +++++----- 2023/day04/src/p2manual_slicing.rs | 54 ++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 2023/day04/src/p2manual_slicing.rs diff --git a/2023/day04/src/lib.rs b/2023/day04/src/lib.rs index 46c32fc..567e7c0 100644 --- a/2023/day04/src/lib.rs +++ b/2023/day04/src/lib.rs @@ -1,6 +1,7 @@ mod p2ascii; mod p2cache; mod p2chunks; +mod p2manual_slicing; mod p2no_alloc; use helper::{Day, Variants}; @@ -22,6 +23,7 @@ helper::define_variants! { no_alloc => crate::p2no_alloc::part2; ascii => crate::p2ascii::part2; chunks => crate::p2chunks::part2; + manual_slicing => crate::p2manual_slicing::part2; } } diff --git a/2023/day04/src/p2chunks.rs b/2023/day04/src/p2chunks.rs index ca647bd..ce44d2e 100644 --- a/2023/day04/src/p2chunks.rs +++ b/2023/day04/src/p2chunks.rs @@ -1,21 +1,22 @@ fn line_match_count(line: &str) -> usize { - let mut numbers = line.split(':').nth(1).unwrap().split("|"); + let line = line.as_bytes(); + fn pack(chunk: &[u8]) -> u16 { + ((chunk[1] as u16) << 8) | (chunk[2] as u16) + } + + let mut numbers = line.split(|&b| b == b':').nth(1).unwrap().split(|&b| b == b'|'); 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) + .map(pack) .collect::>(); - let you_have = numbers.next().unwrap().as_bytes().chunks_exact(3); + let you_have = numbers.next().unwrap().chunks_exact(3).map(pack); you_have - .filter(|have| { - winning.iter().any(|w| { - w == have - }) - }) + .filter(|have| winning.iter().any(|w| w == have)) .count() } diff --git a/2023/day04/src/p2manual_slicing.rs b/2023/day04/src/p2manual_slicing.rs new file mode 100644 index 0000000..c6bfff6 --- /dev/null +++ b/2023/day04/src/p2manual_slicing.rs @@ -0,0 +1,54 @@ +use nom::InputIter; + +fn line_match_count(line: &str) -> usize { + let line = line.as_bytes(); + fn pack(chunk: &[u8]) -> u16 { + ((chunk[1] as u16) << 8) | (chunk[2] as u16) + } + + let colon = line.position(|b| b == b':').unwrap(); + let numbers = &line[(colon + 1)..]; + let pipe = numbers.position(|b| b == b'|').unwrap(); + let winning = &numbers[..(pipe - 1)]; + let you_have = &numbers[(pipe + 1)..]; + + let winning = winning + .chunks_exact(3) + .map(pack) + .collect::>(); + + let you_have = you_have.chunks_exact(3).map(pack); + + 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::>(); + + 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 +}