Skip to content

Commit b2cb5c7

Browse files
committed
Day 19 done.
1 parent b6b3af8 commit b2cb5c7

File tree

7 files changed

+562
-6
lines changed

7 files changed

+562
-6
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2025 James Carman
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package adventofcode.day19
18+
19+
import adventofcode.util.splitByEmptyLines
20+
import adventofcode.util.trie.Trie
21+
22+
fun String.parseTowelsAndPatterns(): Pair<Trie, List<String>> {
23+
val (towelInput, patternInput) = splitByEmptyLines()
24+
val towels = towelInput.split(", ").toSet()
25+
val patterns = patternInput.lines()
26+
val trie = Trie()
27+
towels.forEach { trie.insert(it) }
28+
return trie to patterns
29+
}
30+
31+
fun String.countPossibleDesigns(): Int {
32+
val (trie, patterns) = parseTowelsAndPatterns()
33+
val memory = mutableMapOf<String, Long>()
34+
return patterns.count { countPossibleCombos(it, trie, memory) > 0L }
35+
}
36+
37+
fun String.countDesignCombos(): Long {
38+
val (trie, patterns) = parseTowelsAndPatterns()
39+
val memory = mutableMapOf<String, Long>()
40+
return patterns.sumOf { pattern -> countPossibleCombos(pattern, trie, memory) }
41+
}
42+
43+
fun countPossibleCombos(pattern: String, trie: Trie, memory: MutableMap<String, Long>): Long {
44+
return memory.getOrPut(pattern) {
45+
trie.prefixesOf(pattern)
46+
.sumOf { if (it == pattern) 1L else countPossibleCombos(pattern.removePrefix(it), trie, memory) }
47+
}
48+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2025 James Carman
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package adventofcode.util.trie
18+
19+
class Trie {
20+
21+
private val root: TrieNode = TrieNode("")
22+
23+
fun insert(word: String) {
24+
var current = root
25+
for (char in word) {
26+
current = current.children.getOrPut(char) { TrieNode(current.prefix + char) }
27+
}
28+
current.isEndOfWord = true
29+
}
30+
31+
fun prefixesOf(word: String): List<String> {
32+
var current = root
33+
val prefixes = mutableListOf<String>()
34+
for (char in word) {
35+
if (current.isEndOfWord) {
36+
prefixes.add(current.prefix)
37+
}
38+
current = current.children[char] ?: return prefixes
39+
}
40+
if (current.isEndOfWord) {
41+
prefixes.add(current.prefix)
42+
}
43+
44+
return prefixes
45+
}
46+
47+
fun search(word: String): Boolean {
48+
var current = root
49+
for (char in word) {
50+
current = current.children[char] ?: return false
51+
}
52+
return current.isEndOfWord
53+
}
54+
55+
fun startsWith(prefix: String): Boolean {
56+
var current = root
57+
for (char in prefix) {
58+
current = current.children[char] ?: return false
59+
}
60+
return true
61+
}
62+
}
63+
64+
private class TrieNode(val prefix: String) {
65+
val children: MutableMap<Char, TrieNode> = mutableMapOf()
66+
var isEndOfWord: Boolean = false
67+
}

src/test/kotlin/adventofcode/Day19Test.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,34 @@
1616

1717
package adventofcode
1818

19+
import adventofcode.day19.countPossibleDesigns
20+
import adventofcode.day19.countDesignCombos
1921
import io.kotest.matchers.shouldBe
2022
import org.junit.jupiter.api.Test
2123

2224
class Day19Test {
2325

2426
@Test
2527
fun example1() {
26-
calculatePart1(readExample1()) shouldBe 0
28+
calculatePart1(readExample1()) shouldBe 6
2729
}
2830

2931
@Test
3032
fun part1() {
31-
calculatePart1(readInput()) shouldBe 0
33+
calculatePart1(readInput()) shouldBe 206
3234
}
3335

3436
@Test
3537
fun example2() {
36-
calculatePart2(readExample2()) shouldBe 0
38+
calculatePart2(readExample2()) shouldBe 16L
3739
}
3840

3941
@Test
4042
fun part2() {
41-
calculatePart2(readInput()) shouldBe 0
43+
calculatePart2(readInput()) shouldBe 622121814629343L
4244
}
4345

44-
private fun calculatePart1(input: String): Int = 0
46+
private fun calculatePart1(input: String): Int = input.countPossibleDesigns()
4547

46-
private fun calculatePart2(input: String): Int = 0
48+
private fun calculatePart2(input: String): Long = input.countDesignCombos()
4749
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package adventofcode.util.trie
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
6+
class TrieTest {
7+
@Test
8+
fun `single letter should be a valid prefix`() {
9+
val trie = Trie()
10+
trie.insert("r")
11+
trie.insert("ru")
12+
trie.insert("hello")
13+
trie.insert("ruf")
14+
trie.insert("ruff")
15+
trie.prefixesOf("ruff") shouldBe listOf("r", "ru", "ruf", "ruff")
16+
}
17+
}

src/test/resources/day19-example1.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
r, wr, b, g, bwu, rb, gb, br
2+
3+
brwrr
4+
bggr
5+
gbbr
6+
rrbgbr
7+
ubwu
8+
bwurrg
9+
brgr
10+
bbrgwb

src/test/resources/day19-example2.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
r, wr, b, g, bwu, rb, gb, br
2+
3+
brwrr
4+
bggr
5+
gbbr
6+
rrbgbr
7+
ubwu
8+
bwurrg
9+
brgr
10+
bbrgwb

0 commit comments

Comments
 (0)