Skip to content

Commit

Permalink
Optimize 2024-19
Browse files Browse the repository at this point in the history
  • Loading branch information
fornwall committed Dec 19, 2024
1 parent 26ab436 commit 6622da3
Showing 1 changed file with 43 additions and 42 deletions.
85 changes: 43 additions & 42 deletions crates/core/src/year2024/day19.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
use crate::input::{on_error, Input};

const NUM_NODES: usize = 1024;
const MAX_TRIE_NODES: usize = 1024;
const MAX_DESIGN_LEN: usize = 64;

pub fn solve(input: &Input) -> Result<u64, String> {
let (patterns, designs) = input.text.split_once("\n\n").ok_or_else(on_error)?;

let trie = patterns.split(", ").collect::<Trie>();
let trie = Trie::try_from_iter(patterns.split(", "))?;

let ceil = input.part_values(1, u64::MAX);
Ok(designs
designs
.lines()
.map(|design| trie.count(design).min(ceil))
.sum())
.map(|design| {
if design.len() > MAX_DESIGN_LEN {
Err(format!("Too long design - max {MAX_DESIGN_LEN} supported"))
} else {
Ok(trie.count(design).min(ceil))
}
})
.sum()
}

#[derive(Clone, Copy)]
Expand All @@ -21,7 +28,7 @@ struct TrieNode {
}

struct Trie {
nodes: [TrieNode; NUM_NODES],
nodes: [TrieNode; MAX_TRIE_NODES],
num_allocated: u16,
}

Expand All @@ -31,36 +38,38 @@ impl Default for Trie {
nodes: [TrieNode {
continuations: [u16::MAX; 5],
terminal: false,
}; NUM_NODES],
}; MAX_TRIE_NODES],
num_allocated: 1,
}
}
}

impl<'a> FromIterator<&'a str> for Trie {
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
impl Trie {
fn try_from_iter<'a, I: Iterator<Item = &'a str>>(iter: I) -> Result<Self, String> {
let mut trie = Self::default();
for word in iter {
trie.add(word);
trie.add(word)?;
}
trie
Ok(trie)
}
}

impl Trie {
fn add(&mut self, word: &str) {
fn add(&mut self, word: &str) -> Result<(), String> {
let mut current_node = &mut self.nodes[0];
for b in word.bytes() {
let child_node_idx = Self::map_to_range(b);
let mut child_idx = current_node.continuations[child_node_idx as usize];
if child_idx == u16::MAX {
child_idx = self.num_allocated;
if child_idx as usize >= MAX_TRIE_NODES {
return Err("Too many patterns".to_string());
}
current_node.continuations[child_node_idx as usize] = child_idx;
self.num_allocated += 1;
}
current_node = &mut self.nodes[child_idx as usize];
}
current_node.terminal = true;
Ok(())
}

const fn map_to_range(color: u8) -> u8 {
Expand All @@ -75,34 +84,26 @@ impl Trie {
}

fn count(&self, pattern: &str) -> u64 {
let mut cache = [u64::MAX; NUM_NODES];
self.count_worker(pattern, &mut cache, 0)
}

fn count_worker(&self, towel: &str, cache: &mut [u64; NUM_NODES], offset: usize) -> u64 {
if cache[offset] != u64::MAX {
return cache[offset];
}
let mut current_node = &self.nodes[0];
let mut result = 0;
for (internal_offset, b) in towel.bytes().skip(offset).enumerate() {
let child_offset = Self::map_to_range(b);
let child_idx = current_node.continuations[child_offset as usize];
if child_idx == u16::MAX {
break;
}
current_node = &self.nodes[child_idx as usize];
if current_node.terminal {
let new_offset = offset + internal_offset + 1;
if new_offset == towel.len() {
result += 1;
} else {
result += self.count_worker(towel, cache, new_offset);
let pattern = pattern.as_bytes();
let mut endings_at = [0; MAX_DESIGN_LEN];

for start in 0..pattern.len() {
let num_starts = if start == 0 { 1 } else { endings_at[start - 1] };
if num_starts > 0 {
let mut current_node = &self.nodes[0];

for end in start..pattern.len() {
let child_offset = Self::map_to_range(pattern[end]);
let child_idx = current_node.continuations[child_offset as usize];
if child_idx == u16::MAX {
break;
}
current_node = &self.nodes[child_idx as usize];
endings_at[end] += u64::from(current_node.terminal) * num_starts;
}
}
}
cache[offset] = result;
result
endings_at[pattern.len() - 1]
}
}

Expand All @@ -111,9 +112,9 @@ pub fn tests() {
use crate::input::{test_part_one_no_allocations, test_part_two_no_allocations};

let mut trie = Trie::default();
trie.add("wub");
trie.add("wuu");
trie.add("bbb");
trie.add("wub").unwrap();
trie.add("wuu").unwrap();
trie.add("bbb").unwrap();
assert_eq!(trie.count("wub"), 1);
assert_eq!(trie.count("wuu"), 1);
assert_eq!(trie.count("bbb"), 1);
Expand Down

1 comment on commit 6622da3

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@                     Benchmark Difference                     @@
#      Name   Old (instructions)   New (instructions)   Change (%)
  2024_20_1           10,000,000           10,000,000            0
  2024_20_2           10,000,000           10,000,000            0
  2024_21_1           10,000,000           10,000,000            0
  2024_21_2           10,000,000           10,000,000            0
  2024_22_1           10,000,000           10,000,000            0
  2024_22_2           10,000,000           10,000,000            0
  2024_23_1           10,000,000           10,000,000            0
  2024_23_2           10,000,000           10,000,000            0
  2024_24_1           10,000,000           10,000,000            0
  2024_24_2           10,000,000           10,000,000            0
  2024_25_1           10,000,000           10,000,000            0
   2024_1_1            1,041,087            1,041,087            0
   2024_1_2            1,070,179            1,070,179            0
   2024_2_1            1,741,515            1,741,515            0
   2024_2_2            1,962,906            1,962,906            0
   2024_3_1              227,380              227,380            0
   2024_3_2              317,753              317,753            0
   2024_4_1            1,213,772            1,213,772            0
   2024_4_2              453,902              453,902            0
   2024_5_1            1,605,047            1,605,047            0
   2024_5_2            1,718,989            1,718,989            0
   2024_6_1              641,455              641,455            0
   2024_6_2          141,310,079          141,310,079            0
   2024_7_1            2,466,892            2,466,892            0
   2024_7_2            3,758,401            3,758,401            0
   2024_8_1               44,406               44,406            0
   2024_8_2               86,863               86,863            0
   2024_9_1              897,539              897,539            0
   2024_9_2            2,497,019            2,497,019            0
  2024_10_1            1,087,488            1,087,488            0
  2024_10_2            1,089,387            1,089,387            0
  2024_11_1            3,848,330            3,848,330            0
  2024_11_2           13,462,273           13,462,314            0
  2024_12_1            7,663,695            7,663,695            0
  2024_12_2            7,942,246            7,942,246            0
  2024_13_1              910,454              910,454            0
  2024_13_2              910,208              910,208            0
  2024_14_1              593,112              593,112            0
  2024_14_2           13,416,623           13,416,623            0
  2024_15_1            1,913,993            1,913,993            0
  2024_15_2           59,667,648           59,667,648            0
  2024_16_1           18,233,704           18,233,704            0
  2024_16_2           18,321,270           18,321,270            0
  2024_17_1               11,725               11,725            0
  2024_17_2              218,087              218,087            0
  2024_18_1            1,103,427            1,103,427            0
  2024_18_2            1,427,027            1,427,027            0
+ 2024_19_1            8,200,666            2,242,629          -72
+ 2024_19_2            8,200,146            2,242,689          -72
Benchmark Instructions (count) Instructions (%)
2024_6_2 141,310,079 32.9
2024_15_2 59,667,648 13.9
2024_16_2 18,321,270 4.3
2024_16_1 18,233,704 4.2
2024_11_2 13,462,314 3.1
2024_14_2 13,416,623 3.1
2024_25_1 10,000,000 2.3
2024_24_2 10,000,000 2.3
2024_24_1 10,000,000 2.3
2024_23_2 10,000,000 2.3
2024_23_1 10,000,000 2.3
2024_22_2 10,000,000 2.3
2024_22_1 10,000,000 2.3
2024_21_2 10,000,000 2.3
2024_21_1 10,000,000 2.3
2024_20_2 10,000,000 2.3
2024_20_1 10,000,000 2.3
2024_12_2 7,942,246 1.8
2024_12_1 7,663,695 1.8
2024_11_1 3,848,330 0.9
2024_7_2 3,758,401 0.9
2024_9_2 2,497,019 0.6
2024_7_1 2,466,892 0.6
2024_19_2 2,242,689 0.5
2024_19_1 2,242,629 0.5
2024_2_2 1,962,906 0.5
2024_15_1 1,913,993 0.4
2024_2_1 1,741,515 0.4
2024_5_2 1,718,989 0.4
2024_5_1 1,605,047 0.4
2024_18_2 1,427,027 0.3
2024_4_1 1,213,772 0.3
2024_18_1 1,103,427 0.3
2024_10_2 1,089,387 0.3
2024_10_1 1,087,488 0.3
2024_1_2 1,070,179 0.2
2024_1_1 1,041,087 0.2
2024_13_1 910,454 0.2
2024_13_2 910,208 0.2
2024_9_1 897,539 0.2
2024_6_1 641,455 0.1
2024_14_1 593,112 0.1
2024_4_2 453,902 0.1
2024_3_2 317,753 0.1
2024_3_1 227,380 0.1
2024_17_2 218,087 0.1
2024_8_2 86,863 0.0
2024_8_1 44,406 0.0
2024_17_1 11,725 0.0

Please sign in to comment.