-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDay19.kt
70 lines (60 loc) · 2.33 KB
/
Day19.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*
* Copyright (c) 2020 by Todd Ginsberg
*/
/**
* Advent of Code 2020, Day 19 - Monster Messages
* Problem Description: http://adventofcode.com/2020/day/19
* Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2020/day19/
*/
package com.ginsberg.advent2020
class Day19(input: List<String>) {
private val rules: MutableMap<Int, List<List<Rule>>> = parseRules(input)
private val messages: List<String> = input.dropWhile { it.isNotBlank() }.drop(1)
fun solvePart1(): Int = countRuleMatches()
fun solvePart2(): Int {
rules[8] = listOf(
listOf(RuleReference(42)),
listOf(RuleReference(42), RuleReference(8))
)
rules[11] = listOf(
listOf(RuleReference(42), RuleReference(31)),
listOf(RuleReference(42), RuleReference(11), RuleReference(31))
)
return countRuleMatches()
}
private fun countRuleMatches(): Int =
messages.count { message ->
message.ruleMatch(0).any { it == message.length }
}
private fun parseRules(input: List<String>): MutableMap<Int, List<List<Rule>>> =
input.takeWhile{ it.isNotBlank() }.map { line ->
val (id, rhs) = line.split(": ")
val sides = rhs.split(" | ")
id.toInt() to sides.map { side ->
side.split(' ').map { part ->
if (part.startsWith('"')) Atom(part[1])
else RuleReference(part.toInt())
}
}
}.toMap().toMutableMap()
private fun String.ruleMatch(ruleId: Int, position: Int = 0): List<Int> =
rules.getValue(ruleId).flatMap { listOfRules -> // OR Rule
var positions = listOf(position)
listOfRules.forEach { rule -> // AND Rule
positions = positions.mapNotNull { idx ->
when {
rule is Atom && getOrNull(idx) == rule.symbol ->
listOf(idx + 1) // End condition
rule is RuleReference ->
ruleMatch(rule.id, idx)
else ->
null
}
}.flatten()
}
positions
}
interface Rule
class Atom(val symbol: Char) : Rule
class RuleReference(val id: Int) : Rule
}