@@ -2,101 +2,118 @@ package tr.emreone.adventofcode.days
22
33import tr.emreone.kotlin_utils.automation.Day
44import tr.emreone.kotlin_utils.automation.extractAllIntegers
5- import tr.emreone.kotlin_utils.math.Coords
6- import tr.emreone.kotlin_utils.math.Direction4
7- import tr.emreone.kotlin_utils.math.plus
85
9- class Day19 : Day (19 , 2023 , " Aplenty" ) {
6+ enum class Category (name : String ) {
7+ X (" Extremely cool looking" ),
8+ M (" Musical" ),
9+ A (" Aerodynamic" ),
10+ S (" Shiny" )
11+ }
1012
11- private val workflows = inputAsGroups[0 ].map {
12- val name = it.substringBefore(' {' )
13- val rules = it.substringAfter(' {' ).dropLast(1 ).split(' ,' ).map { r ->
14- if (' :' in r) {
15- val (c, n) = r.split(' :' )
16- val category = when (c[0 ]) {
17- ' x' -> 0
18- ' m' -> 1
19- ' a' -> 2
20- ' s' -> 3
21- else -> error(r)
22- }
23- when (c[1 ]) {
24- ' >' -> Rule .GreaterThan (category, c.first { it.isDigit() }.digitToInt(), n)
25- ' <' -> Rule .LessThan (category, c.first { it.isDigit() }.digitToInt(), n)
26- else -> error(r)
27- }
28- }
29- else
30- Rule .Unconditional (r)
31- }
32- Workflow (name, rules)
33- }.associateBy { it.name }.show()
13+ typealias PotentialPart = Map <Category , IntRange >
3414
35- private val parts = inputAsGroups[1 ].map { it.extractAllIntegers() }.show()
15+ fun PotentialPart.patch (category : Category , newRange : IntRange ? ): PotentialPart ? {
16+ return newRange?.let { patched ->
17+ val parts = this .toMutableMap()
18+ parts[category] = patched
3619
37- data class Workflow (val name : String , val rules : List <Rule >)
20+ parts.toMap()
21+ }
22+ }
23+
24+ class Day19 : Day (19 , 2023 , " Aplenty" ) {
3825
3926 sealed interface Rule {
4027 val next: String
41- fun matches (part : List < Int >): Boolean
28+ fun matches (part : Map < Category , Int >): Boolean
4229 fun split (parts : PotentialPart ): Pair <PotentialPart ?, PotentialPart ?>
4330
44- data class LessThan (val category : Int , val value : Int , override val next : String ) : Rule {
45- override fun matches (part : List < Int >) = part[category] < value
31+ data class LessThan (val category : Category , val value : Int , override val next : String ) : Rule {
32+ override fun matches (part : Map < Category , Int >) = part[category]!! < value
4633
4734 override fun split (parts : PotentialPart ): Pair <PotentialPart ?, PotentialPart ?> {
48- val relevant = parts[category]
35+ val relevant = parts[category]!!
4936 val (matching, notMatching) =
5037 when {
51- value in relevant ->
38+ value in relevant ->
5239 (relevant.first.. < value) to (value.. relevant.last)
5340
5441 value > relevant.last ->
5542 relevant to null
5643
57- else -> null to null
44+ else -> null to null
5845 }
5946 return parts.patch(category, matching) to parts.patch(category, notMatching)
6047 }
6148 }
6249
63- data class GreaterThan (val category : Int , val value : Int , override val next : String ) : Rule {
64- override fun matches (part : List < Int >) = part[category] > value
50+ data class GreaterThan (val category : Category , val value : Int , override val next : String ) : Rule {
51+ override fun matches (part : Map < Category , Int >) = part[category]!! > value
6552
6653 override fun split (parts : PotentialPart ): Pair <PotentialPart ?, PotentialPart ?> {
67- val relevant = parts[category]
54+ val relevant = parts[category]!!
6855 val (matching, notMatching) =
6956 when {
70- value in relevant ->
57+ value in relevant ->
7158 ((value + 1 ).. relevant.last) to (relevant.first.. value)
7259
7360 value < relevant.first ->
7461 relevant to null
7562
76- else -> null to null
63+ else -> null to null
7764 }
7865 return parts.patch(category, matching) to parts.patch(category, notMatching)
7966 }
8067 }
8168
8269 data class Unconditional (override val next : String ) : Rule {
83- override fun matches (part : List < Int >) = true
70+ override fun matches (part : Map < Category , Int >) = true
8471
8572 override fun split (parts : PotentialPart ): Pair <PotentialPart ?, PotentialPart ?> =
8673 parts to null
8774 }
75+ }
76+
77+ data class Workflow (val name : String , val rules : List <Rule >)
8878
89- fun List<IntRange>.patch (category : Int , newRange : IntRange ? ): List <IntRange >? =
90- newRange?.let { patched ->
91- mapIndexed { index, range ->
92- patched.takeIf { index == category } ? : range
79+ private val workflows = inputAsGroups[0 ]
80+ .map {
81+ val (name, ruleString) = it.split(' {' )
82+ val rules = ruleString.dropLast(1 )
83+ .split(' ,' )
84+ .map { r ->
85+ if (' :' in r) {
86+ val (c, next) = r.split(' :' )
87+ val category = when (c[0 ]) {
88+ ' x' -> Category .X
89+ ' m' -> Category .M
90+ ' a' -> Category .A
91+ ' s' -> Category .S
92+ else -> error(r)
93+ }
94+ when (c[1 ]) {
95+ ' >' -> Rule .GreaterThan (category, c.split(' >' )[1 ].toInt(), next)
96+ ' <' -> Rule .LessThan (category, c.split(' <' )[1 ].toInt(), next)
97+ else -> error(r)
98+ }
99+ } else {
100+ Rule .Unconditional (r)
101+ }
93102 }
94- }
95- }
96103
97- override fun part1 (): Int {
104+ Workflow (name, rules)
105+ }
106+ .associateBy { it.name }
107+ .show()
98108
99- fun List<Int>.isAccepted (): Boolean {
109+ private val partRatings = inputAsGroups[1 ]
110+ .map {
111+ Category .entries.zip(it.extractAllIntegers()).toMap()
112+ }
113+ .show()
114+
115+ override fun part1 (): Int {
116+ fun Map <Category , Int >.isAccepted (): Boolean {
100117 var wf = " in"
101118 while (true ) {
102119 if (wf == " R" ) return false
@@ -105,38 +122,37 @@ class Day19 : Day(19, 2023, "Aplenty") {
105122 }
106123 }
107124
108- return parts.filter { it.isAccepted() }.sumOf { it.sum() }
125+ return partRatings
126+ .filter { it.isAccepted() }
127+ .sumOf { it.values.sum() }
109128 }
110129
111130 override fun part2 (): Long {
112- val potentialPart = listOf (
113- 1 .. 4000 ,
114- 1 .. 4000 ,
115- 1 .. 4000 ,
116- 1 .. 4000 ,
131+ val potentialParts = mapOf (
132+ Category . X to 1 .. 4000 ,
133+ Category . M to 1 .. 4000 ,
134+ Category . A to 1 .. 4000 ,
135+ Category . S to 1 .. 4000 ,
117136 )
118137
119138 fun countAccepted (wf : Workflow , parts : PotentialPart ? ): Long =
120139 wf.rules.fold(parts to 0L ) { (remaining, count), rule ->
121140 if (remaining != null ) {
122141 val (matching, notMatching) = rule.split(remaining)
123142 notMatching to count + when (rule.next) {
124- " A" -> matching?.combinations() ? : 0
125- " R" -> 0
143+ " A" -> matching?.combinations() ? : 0
144+ " R" -> 0
126145 else -> countAccepted(workflows[rule.next]!! , matching)
127146 }
128- }
129- else
147+ } else
130148 null to count
131149 }.second
132150
133- return countAccepted(workflows[" in" ]!! , potentialPart )
151+ return countAccepted(workflows[" in" ]!! , potentialParts )
134152 }
135153
136154 private fun PotentialPart.combinations (): Long =
137- this .map { r -> r.last - r.first + 1L }
138- .reduce { acc, i -> acc * i }
139-
155+ this .values.fold( 1 ) { acc, i ->
156+ acc * (i.last - i.first + 1L )
157+ }
140158}
141-
142- typealias PotentialPart = List <IntRange >
0 commit comments