Skip to content

Commit ecb2e5d

Browse files
committed
day 19 part two
1 parent 8710453 commit ecb2e5d

File tree

2 files changed

+66
-35
lines changed

2 files changed

+66
-35
lines changed

2024/day_19/src/lib.rs

+56-22
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
#[derive(Debug)]
32
pub struct Trie {
43
children: [Option<Box<Trie>>; 5],
@@ -14,15 +13,14 @@ impl Trie {
1413
}
1514

1615
fn index_stripe(stripe: char) -> usize {
17-
// allos us to use a super sparse children array
16+
// allows us to use a super sparse children array
1817
match stripe {
1918
'b' => 0,
2019
'g' => 1,
2120
'r' => 2,
2221
'u' => 3,
2322
'w' => 4,
24-
_ => panic!("That towel stripe is not allowed in this onsen")
25-
23+
_ => panic!("That towel stripe is not allowed in this onsen"),
2624
}
2725
}
2826

@@ -34,37 +32,36 @@ impl Trie {
3432
current = current.children[i].get_or_insert_with(|| Box::new(Trie::new()));
3533
}
3634
current.is_word = true;
37-
3835
}
3936

40-
pub fn get_prefixes<'a>(&self, towel: &'a str) -> Vec<&'a str>{
37+
pub fn get_prefixes<'a>(&self, towel: &'a str) -> Vec<&'a str> {
4138
let mut current = self;
42-
let mut prefixes:Vec<&str> = vec![];
39+
let mut prefixes: Vec<&str> = vec![];
4340

44-
for (len, stripe) in towel.chars().enumerate(){
41+
for (len, stripe) in towel.chars().enumerate() {
4542
let i = Trie::index_stripe(stripe);
46-
43+
4744
if let Some(next) = &current.children[i] {
4845
if next.is_word {
4946
prefixes.push(&towel[..=len])
5047
}
5148
current = next
5249
} else {
53-
return prefixes
50+
return prefixes;
5451
}
5552
}
5653
prefixes
5754
}
5855

5956
pub fn is_possible(&self, towel: &str) -> bool {
6057
let n = towel.len();
61-
let mut memo = vec![false;n+1];
58+
let mut memo = vec![false; n + 1];
6259
memo[0] = true;
6360
for start in 0..n {
6461
if memo[start] {
6562
for prefix in self.get_prefixes(&towel[start..]) {
6663
let end = start + prefix.len();
67-
memo[end] =true;
64+
memo[end] = true;
6865
if n == end {
6966
return true;
7067
}
@@ -73,6 +70,25 @@ impl Trie {
7370
}
7471
memo[n]
7572
}
73+
74+
pub fn count_possible(&self, towel: &str) -> u64 {
75+
// this is basically identical to is_possible
76+
// but without the early exit
77+
let n = towel.len();
78+
let mut memo = vec![0; n + 1];
79+
memo[0] = 1;
80+
for start in 0..n {
81+
if memo[start] > 0 {
82+
for prefix in self.get_prefixes(&towel[start..]) {
83+
let end = start + prefix.len();
84+
if end <= n {
85+
memo[end] += memo[start];
86+
}
87+
}
88+
}
89+
}
90+
memo[n]
91+
}
7692
}
7793

7894
#[cfg(test)]
@@ -83,23 +99,41 @@ mod test {
8399
let mut t = Trie::new();
84100
t.insert("bwg");
85101
t.insert("bwgr");
86-
102+
87103
assert_eq!(t.get_prefixes("bwgrra"), vec!["bwg", "bwgr"]);
88104
}
89105

90106
#[test]
91107
fn test_possible() {
92108
let mut t = Trie::new();
93109
["r", "wr", "b", "g", "bwu", "rb", "gb", "br"]
94-
.iter().for_each(|p| t.insert(p));
110+
.iter()
111+
.for_each(|p| t.insert(p));
95112

96-
// assert_eq!(t.is_possible("brwrr"), true);
97-
// assert_eq!(t.is_possible("bggr"), true);
98-
// assert_eq!(t.is_possible("gbbr"), true);
99-
// assert_eq!(t.is_possible("rrbgbr"), true);
100-
// assert_eq!(t.is_possible("ubwu"), false);
101-
// assert_eq!(t.is_possible("bwurrg"), true);
102-
// assert_eq!(t.is_possible("brgr"), true);
113+
assert_eq!(t.is_possible("brwrr"), true);
114+
assert_eq!(t.is_possible("bggr"), true);
115+
assert_eq!(t.is_possible("gbbr"), true);
116+
assert_eq!(t.is_possible("rrbgbr"), true);
117+
assert_eq!(t.is_possible("ubwu"), false);
118+
assert_eq!(t.is_possible("bwurrg"), true);
119+
assert_eq!(t.is_possible("brgr"), true);
103120
assert_eq!(t.is_possible("bbrgwb"), false);
104121
}
105-
}
122+
123+
#[test]
124+
fn count_possible() {
125+
let mut t = Trie::new();
126+
["r", "wr", "b", "g", "bwu", "rb", "gb", "br"]
127+
.iter()
128+
.for_each(|p| t.insert(p));
129+
130+
assert_eq!(t.count_possible("brwrr"), 2);
131+
assert_eq!(t.count_possible("bggr"), 1);
132+
assert_eq!(t.count_possible("gbbr"), 4);
133+
assert_eq!(t.count_possible("rrbgbr"), 6);
134+
assert_eq!(t.count_possible("ubwu"), 0);
135+
assert_eq!(t.count_possible("bwurrg"), 1);
136+
assert_eq!(t.count_possible("brgr"), 2);
137+
assert_eq!(t.count_possible("bbrgwb"), 0);
138+
}
139+
}

2024/day_19/src/main.rs

+10-13
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,27 @@
1-
use std::fs;
21
use day_19::*;
2+
use std::fs;
33

4-
fn parse(s:&str) -> (Trie, Vec<String>) {
4+
fn parse(s: &str) -> (Trie, Vec<String>) {
55
let (patterns, designs) = s.split_once("\n\n").unwrap();
66
let mut prefixes = Trie::new();
77
for p in patterns.split(", ") {
88
prefixes.insert(p.trim());
9-
};
10-
let designs = designs.split("\n")
11-
.map(|line| line.to_owned())
12-
.collect();
9+
}
10+
let designs = designs.split("\n").map(|line| line.to_owned()).collect();
1311

1412
(prefixes, designs)
1513
}
1614

17-
fn part_one<'a>(prefixes: &Trie, towels: &[String]) -> usize {
18-
towels
19-
.iter()
20-
.filter(|t| prefixes.is_possible(t))
21-
.count()
22-
15+
fn part_one(prefixes: &Trie, towels: &[String]) -> usize {
16+
towels.iter().filter(|t| prefixes.is_possible(t)).count()
17+
}
18+
fn part_two(prefixes: &Trie, towels: &[String]) -> u64 {
19+
towels.iter().map(|t| prefixes.count_possible(t)).sum()
2320
}
2421

2522
fn main() {
2623
let s = fs::read_to_string("data.txt").expect("we lost the designs file!");
2724
let (prefixes, designs) = parse(&s);
2825
println!("{:?}", part_one(&prefixes, &designs));
29-
println!("{:?}", prefixes.is_possible("gwwgwbgbgbuugwurgggwrubrruuwgbwgwrgwrbwrugwwrrugrwgu"));
26+
println!("{:?}", part_two(&prefixes, &designs));
3027
}

0 commit comments

Comments
 (0)