Day 5: Cafeteria
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465


Kotlin
I like this one. The first part could be solved trivially with a naive approach. The second part is also not too complicated.
I started out with a simple merging algorithm that would check all ranges, except the one to merge, for overlaps.
With clever sorting, I can skip the search for mergable ranges and just iterate in reverse and build larger and larger ranges.
I haven’t tried to merge adjacent ranges like 1…2 and 3…4 to 1…4. The solution is fast enough already when JIT/C2 compiled (200-250 µs).
Code on Github
Code
class Day05 : AOCSolution { override val year = 2025 override val day = 5 override fun part1(inputFile: String): String { val (freshIngredients, availableIngredients) = readResourceTwoParts(inputFile) val freshRanges = buildRanges(freshIngredients) val ingredientIds = availableIngredients.lines().filterNot(String::isEmpty).map(String::toLong) val count = ingredientIds.count { id -> freshRanges.any { range -> id in range } } return count.toString() } override fun part2(inputFile: String): String { val (freshIngredients, _) = readResourceTwoParts(inputFile) val freshRanges = buildRanges(freshIngredients) return freshRanges.sumOf { range -> range.last - range.first + 1 }.toString() } private companion object { private fun buildRanges(ingredients: String): List<LongRange> { val lines = ingredients.lines() val ranges = MutableList(lines.size) { i -> val line = lines[i] val hyphen = line.indexOf('-') val lower = line.take(hyphen).toLong() val upper = line.substring(hyphen + 1).toLong() LongRange(lower, upper) } // Sort the ranges // The ones with the smallest ID and the least upper end // get sorted to the beginning. // This allows for easy merging, as overlapping ranges are always adjacent ranges.sortWith(Comparator { r1, r2 -> val first = r1.first.compareTo(r2.first) if (first != 0) { first } else { r1.last.compareTo(r2.last) } }) // Merge adjacent ranges backwards, modifying the list in-place for (i in ranges.lastIndex downTo 1) { val lowerRange = ranges[i - 1] val upperRange = ranges[i] // The two ranges do overlap, because the tail of the first range // is in the second range. if (upperRange.first <= lowerRange.last) { ranges[i - 1] = LongRange( lowerRange.first, maxOf(lowerRange.last, upperRange.last) ) ranges.removeAt(i) } } return ranges } } }