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

  • eco_game@discuss.tchncs.de
    link
    fedilink
    arrow-up
    3
    ·
    2 days ago

    Kotlin

    Pretty simple solution, just plain count / remove the rolls until none can be removed anymore. I would’ve liked to try using imaginary numbers this year (due to this article), but sadly Kotlin doesn’t natively support them and I was too lazy to use a library.

    Solution
    class Day04 : Puzzle {
    
        val grid = mutableListOf<MutableList<Char>>()
    
        override fun readFile() {
            val input = readInputFromFile("src/main/resources/a2025/day04.txt")
            for ((r, line) in input.lines().filter(String::isNotBlank).withIndex()) {
                grid.add(mutableListOf())
                for (char in line) {
                    grid[r].add(char)
                }
            }
        }
    
        override fun solvePartOne(): String {
            return countRolls(grid).toString()
        }
    
        override fun solvePartTwo(): String {
            var sum = 0
            var removed = -1
            while (removed != 0) {
                // main grid is modified here, not the best but doesn't really matter
                // also no idea how to clone 2D list in Kotlin
                removed = countRolls(grid, true)
                sum += removed
            }
            return sum.toString()
        }
    
        private fun countRolls(grid: MutableList<MutableList<Char>>, removeRolls: Boolean = false): Int {
            val dr = listOf(-1, -1, -1, 0, 0, 1, 1, 1)
            val dc = listOf(-1, 0, 1, -1, 1, -1, 0, 1)
    
            var sum = 0
            for (r in grid.indices) {
                for (c in grid[r].indices) {
                    if (grid[r][c] != '@') continue
    
                    var neighborCount = 0
                    for (i in dr.indices) {
                        if (gridGet(grid, r + dr[i], c + dc[i]) == '@') neighborCount++
                    }
                    if (neighborCount < 4) {
                        sum++
                        if (removeRolls) grid[r][c] = '.'
                    }
                }
            }
            return sum
        }
    
        private fun gridGet(grid: List<List<Char>>, r: Int, c: Int, default: Char = '.'): Char {
            return if (r in grid.indices && c in grid[r].indices) {
                grid[r][c]
            } else {
                default
            }
        }
    }
    

    full code on Codeberg

    • Deebster@programming.dev
      link
      fedilink
      English
      arrow-up
      3
      ·
      2 days ago

      Ha, I’ve got that article half-read in a tab somewhere. Same problem here though - they’re not in the standard library for anything I plan to use for AoC.

    • chunkystyles@sopuli.xyz
      link
      fedilink
      English
      arrow-up
      2
      ·
      edit-2
      3 hours ago

      Edit: looking at your code, I had forgotten about .indices. That would have made this a little easier to write.

      I completely forgot to do the puzzle yesterday somehow. I struggled a bit on this one for a while because I’d used a <= 4 where I should have used a < 4. Just a complete brainfart of thinking, “It needs to be 4 or less”. I wasted more time on that than I’d like to admit.

      My first stab at this set all of the adjacency counts to 0, and that lead to a few rolls that had no rolls adjacent to them staying on the map by accident.

      const val toiletPaperRoll = '@'
      const val adjacentLimit = 4
      var height = 0
      var width = 0
      
      fun main() {
          val input = getInput(4)
          val map = parseInput1(input)
          height = map.size
          width = map[0].size
          val adjacencyMap = createAdjacencyMap(map)
          var anyRemoved = true
          var count = 0
          while (anyRemoved) {
              anyRemoved = false
              for (y in 0..<height) {
                  for (x in 0..<width) {
                      if (adjacencyMap[y][x] in 0..<adjacentLimit) {
                          count++
                          anyRemoved = true
                          removeToiletPaperRoll(adjacencyMap, x, y)
                      }
                  }
              }
          }
          println(count)
      }
      
      fun parseInput1(input: String): List<List<Char>> = input
          .lines()
          .filter { it.isNotBlank() }
          .map { it.toCharArray().toList() }
      
      fun createAdjacencyMap(map: List<List<Char>>): List<MutableList<Int>> {
          val adjacencyMap = List(height) { MutableList(width) { -1 } }
          for (y in 0..<height) {
              for (x in 0..<width) {
                  if (map[y][x] != toiletPaperRoll) {
                      continue
                  }
                  adjacencyMap[y][x]++
                  for (y2 in y - 1..y + 1) {
                      for (x2 in x - 1..x + 1) {
                          if (y == y2 && x == x2 || (y2 < 0 || x2 < 0 || y2 >= height || x2 >= width)) {
                              continue
                          }
                          if (map[y2][x2] == toiletPaperRoll) {
                              adjacencyMap[y2][x2]++
                          }
                      }
                  }
              }
          }
          return adjacencyMap
      }
      
      fun removeToiletPaperRoll(adjacencyMap: List<MutableList<Int>>, x: Int, y: Int) {
          adjacencyMap[y][x] = -1
          for (y2 in y - 1..y + 1) {
              for (x2 in x - 1..x + 1) {
                  if (y == y2 && x == x2 || (y2 < 0 || x2 < 0 || y2 >= height || x2 >= width)) {
                      continue
                  }
                  if (adjacencyMap[y2][x2] >= adjacentLimit) {
                      adjacencyMap[y2][x2]--
                  }
              }
          }
      }