Day 4: Printing Department
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’m catching up on this year’s AOC.
This one was rather easy. I already have a pretty versatile grid class that I have just iterated as often as needed.
Doing this one also lead me into the rabbit hole that is source code generation in Gradle. I used this to generate all the implementations for the primitive types of the grid class as primitive arrays are not generic in the JVM.
An
Array<Int>is an array of integer references, but anIntArrayis an array of primitive integers.Code on GitHub
Code
class Day04 : AOCSolution { override val year = 2025 override val day = 4 override fun part1(inputFile: String): String { val grid = readResourceLines(inputFile).map(CharSequence::toList).toCharGrid() var accessiblePaperRolls = 0 // Quickly iterate the grid in top-left to bottom-right order for (y in 0 until grid.height) { for (x in 0 until grid.width) { // Count the neighbours of each paper roll. if (grid[x, y] == PAPER_ROLL && grid.countNeighbours(x, y, 1) { it == PAPER_ROLL } < 4 ) { accessiblePaperRolls++ } } } return accessiblePaperRolls.toString() } override fun part2(inputFile: String): String { val grid = readResourceLines(inputFile).map(CharSequence::toList).toCharGrid() var count = 0 while (true) { var iterationCount = 0 // Quickly iterate the grid in top-left to bottom-right order for (y in 0 until grid.height) { for (x in 0 until grid.width) { if (grid[x, y] == PAPER_ROLL && grid.countNeighbours(x, y, 1) { it == PAPER_ROLL } < 4 ) { // Remove the paper roll for the next iteration grid[x, y] = REMOVED_PAPER_ROLL iterationCount++ } } } count += iterationCount // Repeat the count until no paper rolls are accessible. if (iterationCount == 0) { break } } return count.toString() } private companion object { const val PAPER_ROLL = '@' const val REMOVED_PAPER_ROLL = 'x' /** * Count the neighbours of the given cell in the given [radius] of cells that satisfy the given predicate. * * @param startX the horizontal position of the center of the count in the grid * @param startY the vertical position of the center of the count in the grid * @param radius the radius counted in Manhattan distance to the center * @param predicate the test that needs to pass for a neighbour to count. */ private fun CharGrid.countNeighbours( startX: Int, startY: Int, radius: Int, predicate: Predicate<Char>, ): Int { var count = 0 for (y in maxOf(startY - radius, 0)..minOf(startY + radius, height - 1)) { for (x in maxOf(startX - radius, 0)..minOf(startX + radius, width - 1)) { if (y == startY && x == startX) { continue } if (predicate.test(this[x, y])) { count++ } } } return count } } }