This commit is contained in:
Stefan Forstenlechner 2020-12-19 16:48:11 +01:00
parent 68938c4eed
commit 705e05fbab
1 changed files with 109 additions and 0 deletions

109
day16.kt Normal file
View File

@ -0,0 +1,109 @@
import java.io.File
fun main(args: Array<String>) {
println("Hello day16!")
solve()
}
data class RuleRange(val min: Int, val max: Int)
data class Rule(val name: String, val ruleRangeFirst: RuleRange, val ruleRangeSecond: RuleRange)
val numbersRegex = Regex("\\d+")
fun readRules(ruleAsString: String): Rule {
val (ruleName, rest) = ruleAsString.split(":")
val ruleRanges = numbersRegex.findAll(rest)
.flatMap { match -> match.groupValues.map { it.toInt() } }
.chunked(2)
.map { pair -> RuleRange(pair[0], pair[1]) }
.toList()
return Rule(ruleName, ruleRanges[0], ruleRanges[1])
}
fun checkRuleRange(v: Int, ruleRange: RuleRange): Boolean = v >= ruleRange.min && v <= ruleRange.max
fun errorRateIfViolated(v: Int, rules: List<Rule>): Long {
if (rules.any { rule -> checkRuleRange(v, rule.ruleRangeFirst) || checkRuleRange(v, rule.ruleRangeSecond) }) {
return 0
}
return v.toLong()
}
fun sumErrorRateOfViolations(ticket: String, rules: List<Rule>): Long =
ticket.split(",")
.map { it.toInt() }
.map { errorRateIfViolated(it, rules) }
.sum()
fun isValidValue(v: Int, rules: List<Rule>): Boolean =
rules.any { rule -> checkRuleRange(v, rule.ruleRangeFirst) || checkRuleRange(v, rule.ruleRangeSecond) }
fun isValidTicket(ticket: String, rules: List<Rule>): Boolean =
ticket.split(",")
.map { it.toInt() }
.all { isValidValue(it, rules) }
fun isRuleValidFor(rule: Rule, values: List<Int>): Boolean = values.all { v -> checkRuleRange(v, rule.ruleRangeFirst) || checkRuleRange(v, rule.ruleRangeSecond) }
fun valuesForColumn(ticketValues: List<List<Int>>, col: Int) = ticketValues.map { it[col] }
fun rulesPerColumn(ticketValues: List<List<Int>>, rules: List<Rule>): MutableMap<Rule, MutableSet<Int>> {
val ruleValidForColumn = mutableMapOf<Rule, MutableSet<Int>>()
for (i in ticketValues[0].indices) {
val columnValues = valuesForColumn(ticketValues, i)
for (rule in rules) {
if (isRuleValidFor(rule, columnValues)) {
if (!ruleValidForColumn.containsKey(rule)) {
ruleValidForColumn[rule] = mutableSetOf()
}
ruleValidForColumn[rule]?.add(i)
}
}
}
return ruleValidForColumn
}
fun ruleToColumnAssignment(validRulesPerColumns: MutableMap<Rule, MutableSet<Int>>): Map<Rule, Int> {
val rulePerColumnAssignment = mutableMapOf<Rule, Int>()
while (validRulesPerColumns.isNotEmpty()) {
val currentAssignment = validRulesPerColumns.asSequence().filter { it.value.size == 1 }.first()
val column = currentAssignment.value.first()
rulePerColumnAssignment[currentAssignment.key] = column
validRulesPerColumns.remove(currentAssignment.key)
for (validRulPerColumns in validRulesPerColumns) {
validRulPerColumns.value.remove(column)
}
}
return rulePerColumnAssignment
}
fun solve() {
val readLines = File("day16/input").readText();
val (ruleText, ticketWithLabel, nearbyWithLabel) = readLines.split("\n\n")
val ticket = ticketWithLabel.split("\n")[1]
val nearby = nearbyWithLabel.split("\n").drop(1).filter { it.isNotEmpty() }
val rules = ruleText.split("\n").filter { it.isNotEmpty() }.map { readRules(it) }
val errorRate = nearby.map { sumErrorRateOfViolations(it, rules) }.sum()
println(errorRate)
// part 2
val nearbyValidTickets = nearby.filter { isValidTicket(it, rules) }
val nearbyTicketValues = nearbyValidTickets.map { t -> t.split(",").map { it.toInt() } }
val validRulesPerColumns = rulesPerColumn(nearbyTicketValues, rules)
val ruleToColumnAssignment = ruleToColumnAssignment(validRulesPerColumns)
val ticketValues = ticket.split(",").map { it.toLong() }
val departureProduct = ruleToColumnAssignment.entries.filter { it.key.name.startsWith("departure") }.map { ticketValues[it.value] }.reduce { acc, i -> acc * i }
println(departureProduct)
}