Problem description
This is a 2-dimensional grid problem. The input data is a grid, where each cell can be either empty (.) or contain a roll of paper (@).
..@@.@@@@.
@@@.@.@.@@
@@@@@.@.@@
@.@@@@..@.
@@.@@@@.@@
.@@@@@@@.@
.@.@.@.@@@
@.@@@.@@@@
.@@@@@@@@.
@.@.@@@.@.
In my code, I modelized the grid as a 2-dimensional Array of Booleans.
Part 1
First, we have to calculate how many rolls of paper have fewer than 4 rolls of paper in adjacent positions (horizontally, vertically or diagonally).
So I defined a list of vectors representing coordinate differences between a roll of paper and neighbouring positions.
private val dirs: List[(Int, Int)] = List((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1))
Then, I defined a method that returns the number of adjacent paper rolls.
private def adjacentRolls(grid: Array[Array[Boolean]], row: Int, col: Int): Int =
var rolls = 0
for
dir <- DIRS
if row + dir(0) >= 0 && row + dir(0) < grid.length
if col + dir(1) >= 0 && col + dir(1) < grid.head.length
do
if grid(row + dir(0))(col + dir(1)) then rolls += 1
rolls
Finally, I could use this method to count how many paper rolls have fewer than 4 paper rolls in their neighbourhood.
def solvePart1(input: List[String]): Int =
val grid = input.map(line => line.map(c => c == '@').toArray).toArray
var count = 0
for
row <- 0 until grid.length
col <- 0 until grid.head.length
do
if grid(row)(col) && adjacentRolls(grid, row, col) < 4 then
count += 1
count
Part 2
Now, the paper rolls that have fewer than 4 neighbours are removed from the grid. This process is repeated until no paper roll can be accessed.
My code for Part 2 is a simple loop, with an exit condition (the variable done in my code). At the beginning of each step, the variable done is set to false, and it is set to true whenever an accessible paper roll is found.
Before and after the loop, the number of paper rolls is counted, and the result is the difference between the two numbers.
def solvePart2(input: List[String]): Int =
var grid = input.map(line => line.map(c => c == '@').toArray).toArray
val rolls = grid.flatten.count(c => c == true)
var done = false
while !done do
done = true
var newGrid = (0 until grid.length).map(row => (0 until grid.head.length).map(col => false).toArray).toArray
for
row <- 0 until grid.length
col <- 0 until grid.head.length
if grid(row)(col)
do
if adjacentRolls(grid, row, col) >= 4 then newGrid(row)(col) = true else done = false
grid = newGrid
rolls - grid.flatten.count(c => c == true)