Skip to content

Commit 9ef757b

Browse files
authored
Merge pull request #25 from palinkiewicz/2023_d19
2023 Day 19
2 parents 758465d + 8ff4225 commit 9ef757b

File tree

3 files changed

+939
-0
lines changed

3 files changed

+939
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ I started taking part in the event in 2023 but may also consider doing tasks fro
2525
| [Day 16: The Floor Will Be Lava](https://adventofcode.com/2023/day/16) | [Solution](/adventofcode2023/Day16.kt) | [Inputs](/resources/adventofcode2023/Day16.txt) |
2626
| [Day 17: Clumsy Crucible](https://adventofcode.com/2023/day/17) | [Solution](/adventofcode2023/Day17.kt) | [Inputs](/resources/adventofcode2023/Day17.txt) |
2727
| [Day 18: Lavaduct Lagoon](https://adventofcode.com/2023/day/18) | [Solution](/adventofcode2023/Day18.kt) | [Inputs](/resources/adventofcode2023/Day18.txt) |
28+
| [Day 19: Aplenty](https://adventofcode.com/2023/day/19) | [Solution](/adventofcode2023/Day19.kt) | [Inputs](/resources/adventofcode2023/Day19.txt) |

adventofcode2023/Day19.kt

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package adventofcode2023
2+
3+
import java.io.File
4+
import java.util.LinkedList
5+
6+
object Day19 {
7+
private const val ACCEPT = "A"
8+
private const val REJECT = "R"
9+
private const val STARTING_WORKFLOW = "in"
10+
11+
private val inputs = File("resources/adventofcode2023/Day19.txt")
12+
.readText()
13+
.split("\n\n")
14+
.map { it.split("\n") }
15+
16+
private val workflows = inputs.first().associate { line ->
17+
val split = line.split('{')
18+
val steps = split.last().removeSuffix("}").split(',').map { step ->
19+
val stepSplit = step.split(':')
20+
if (stepSplit.size == 1)
21+
Pair(null, stepSplit.first())
22+
else
23+
Pair(
24+
Condition(
25+
stepSplit.first().first(),
26+
stepSplit.first().drop(1).first(),
27+
stepSplit.first().drop(2).toInt()
28+
),
29+
stepSplit.last()
30+
)
31+
}
32+
split[0] to steps
33+
}
34+
35+
private val parts = inputs.last().map { line ->
36+
val split = line.removeSurrounding("{", "}").split(',')
37+
split.associate {
38+
val rating = it.split('=')
39+
rating.first().first() to rating.last().toInt()
40+
}
41+
}
42+
43+
private data class Condition(val variable: Char, val checker: Char, val value: Int) {
44+
fun check(checked: Map<Char, Int>): Boolean =
45+
checkValue(checked[variable]!!)
46+
47+
fun checkRange(checked: Map<Char, Pair<Int, Int>>): Int =
48+
(if (checkValue(checked[variable]!!.first)) RANGE_LOWER else 0) +
49+
(if (checkValue(checked[variable]!!.second)) RANGE_HIGHER else 0)
50+
51+
private fun checkValue(checkedValue: Int): Boolean =
52+
when (checker) {
53+
'>' -> checkedValue > value
54+
'<' -> checkedValue < value
55+
else -> throw Exception("Unknown checker")
56+
}
57+
58+
companion object {
59+
const val RANGE_NONE = 0
60+
const val RANGE_LOWER = 1
61+
const val RANGE_HIGHER = 2
62+
const val RANGE_BOTH = 3
63+
}
64+
}
65+
66+
private fun checkPart(part: Map<Char, Int>): Boolean {
67+
var currentWorkflow = workflows[STARTING_WORKFLOW]!!
68+
var stepIndex = 0
69+
70+
while (stepIndex < currentWorkflow.size) {
71+
val step = currentWorkflow[stepIndex]
72+
stepIndex++
73+
74+
if (step.first != null && !step.first!!.check(part)) continue
75+
76+
when (step.second) {
77+
ACCEPT -> return true
78+
REJECT -> return false
79+
else -> {
80+
currentWorkflow = workflows[step.second]!!
81+
stepIndex = 0
82+
}
83+
}
84+
}
85+
86+
throw Exception("Couldn't check part")
87+
}
88+
89+
private fun acceptedRanges(): List<Map<Char, Pair<Int, Int>>> {
90+
// Map of values (x, m, a, s), Workflow name, Workflow step index
91+
val ranges = LinkedList<Triple<Map<Char, Pair<Int, Int>>, String, Int>>()
92+
93+
val accepted = mutableListOf<Map<Char, Pair<Int, Int>>>()
94+
95+
ranges.add(Triple(mapOf(
96+
'x' to Pair(1, 4000),
97+
'm' to Pair(1, 4000),
98+
'a' to Pair(1, 4000),
99+
's' to Pair(1, 4000)
100+
), STARTING_WORKFLOW, 0))
101+
102+
while (ranges.isNotEmpty()) {
103+
val range = ranges.removeFirst()
104+
val (valueRanges, workflowName, stepIndex) = range
105+
106+
when (workflowName) {
107+
ACCEPT -> {
108+
accepted.add(valueRanges)
109+
continue
110+
}
111+
REJECT -> continue
112+
}
113+
114+
val step = workflows[workflowName]!![stepIndex]
115+
116+
if (step.first != null) {
117+
val condition = step.first!!
118+
val (variable, _, value) = condition
119+
120+
fun createTriple(
121+
changeWorkflow: Boolean, firstValue: Int = -1, secondValue: Int = -1
122+
): Triple<Map<Char, Pair<Int, Int>>, String, Int> {
123+
val newRangeMap = valueRanges.toMutableMap().apply {
124+
if (firstValue >= 0) this[variable] = this[variable]!!.copy(first = firstValue)
125+
if (secondValue >= 0) this[variable] = this[variable]!!.copy(second = secondValue)
126+
}
127+
128+
return Triple(newRangeMap, if (changeWorkflow) step.second else workflowName, if (changeWorkflow) 0 else stepIndex + 1)
129+
}
130+
131+
when (condition.checkRange(valueRanges)) {
132+
Condition.RANGE_NONE -> {
133+
ranges.add(Triple(valueRanges, workflowName, stepIndex + 1))
134+
}
135+
Condition.RANGE_LOWER -> {
136+
ranges.add(createTriple(true, secondValue = value - 1))
137+
ranges.add(createTriple(false, firstValue = value))
138+
}
139+
Condition.RANGE_HIGHER -> {
140+
ranges.add(createTriple(true, firstValue = value + 1))
141+
ranges.add(createTriple(false, secondValue = value))
142+
}
143+
Condition.RANGE_BOTH -> {
144+
ranges.add(Triple(valueRanges, step.second, 0))
145+
}
146+
}
147+
} else {
148+
ranges.add(Triple(valueRanges, step.second, 0))
149+
}
150+
}
151+
152+
return accepted
153+
}
154+
155+
fun part1() = println(parts.filter { checkPart(it) }.sumOf { it.values.sum() })
156+
157+
fun part2() = println(acceptedRanges().sumOf { ranges ->
158+
ranges.values.fold(1L) { acc, pair -> acc * (pair.second - pair.first + 1) }
159+
})
160+
}
161+
162+
fun main() {
163+
Day19.part1()
164+
Day19.part2()
165+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy