# Advent Of Code 2025 - Day 4

# Introduction

Today’s puzzle was about grid traversal and simulating process. Let me setup the scenario.

We are there at the printing department. And we need the forklift for the commute process, but the forklifts are used by the elves for moving heavy rolls of wrapping paper. We need to optimize their workflow, so that the forklifts become free ASAP.

Now comes the important part, the paper rolls are arranged in a grid, and in the given representation, a paper roll is represented by `@`. For example,

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764849630860/7ea6fa8c-cae6-4da8-b3ec-aa188bdae847.png align="left")

In this grid a *forklift* can access/lift a paper roll if there are ***fewer than four*** in the eight adjacent positions. In the above example, the rolls that can be accessed are marked `x`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764849931719/f638d843-f66e-40d0-b8a1-98daad425ad9.png align="left")

# Puzzle 1

First puzzle was quite simple simple, we simply had to count the number of liftable rolls. In the given example, it is \\(13\\).

Let me tell you a little bit about the adjacent positions. In a grid, for a position `(i, j)`, the adjacent positions are the following. Its the positions at units distance from that position in vertical or horizontal or diagonal direction. In the figure below for blue position, the green position are called **adjancent**.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764850328951/449af7e9-cc8d-4f1b-9b8e-0fc7f915ce1d.jpeg align="center")

## Solution and Implementation

We will simply check at each of the eight positions, that if they exist(they don’t for border elements) and if they are paper roll and count them, if that `count < 4`, count it in ans.

```cpp
for (int i = 0; i < grid.size(); ++i) {
    for (int j = 0; j < grid[0].size(); ++j) {
      if (grid[i][j] != '@')
        continue;
      int count =
          // N
          (i >= 1 && grid[i - 1][j] == '@') +
          // NW
          (i >= 1 && j >= 1 && grid[i - 1][j - 1] == '@') +
          // W
          (j >= 1 && grid[i][j - 1] == '@') +
          // SW
          (j >= 1 && i < grid.size() - 1 && grid[i + 1][j - 1] == '@') +
          // S
          (i < grid.size() - 1 && grid[i + 1][j] == '@') +
          // SE
          (j < grid[0].size() - 1 && i < grid.size() - 1 &&
           grid[i + 1][j + 1] == '@') +
          // E
          (j < grid[0].size() - 1 && grid[i][j + 1] == '@') +
          // NE  ← missing one
          (i >= 1 && j < grid[0].size() - 1 && grid[i - 1][j + 1] == '@');
      if (count < 4)
        ans++; // count as liftable
    }
  }
```

# Puzzle 2

> Now the Elves just need help accessing as much of the paper as they can.
> 
> Once a roll of paper can be accessed by a forklift, it can be *removed*. Once a roll of paper is removed, the forklifts might be able to access *more* rolls of paper, which they might also be able to remove. How many total rolls of paper could the Elves remove if they keep repeating this process?

In simple words, we remove the removable ones, then remove more(if possible) until we are left with such situation, that we can’t remove anymore. In the above example, the simulation/solution is present [here](https://adventofcode.com/2025/day/4#part2).

## Solution

We can’t remove the removable paper rolls on the first pass(where we are checking if they are removable or not) as that might hinder the verification of other rolls, instead we just ***mark*** them, and then after this pass, we remove them(just mark them `.`). And repeat this process, until nothing is marked in first pass

## Implementation

In my implementation, I used a list of positions that are supposed to be marked. When I have to mark them, I just push them in this list. If nothing is in the list after this pass we just stop the whole process, else we remove(marking them `.` in the grid) all the positions while also adding the list’s original size to the final solution.

```cpp
  int final_ans = 0;
  list<pair<int, int>> positions;
  do {
    positions.clear();
    for (int i = 0; i < grid.size(); ++i) {
      for (int j = 0; j < grid[0].size(); ++j) {
        if (grid[i][j] != '@')
          continue;
        int cnt =
            // N
            (i >= 1 && grid[i - 1][j] == '@') +
            // NW
            (i >= 1 && j >= 1 && grid[i - 1][j - 1] == '@') +
            // W
            (j >= 1 && grid[i][j - 1] == '@') +
            // SW
            (j >= 1 && i < grid.size() - 1 && grid[i + 1][j - 1] == '@') +
            // S
            (i < grid.size() - 1 && grid[i + 1][j] == '@') +
            // SE
            (j < grid[0].size() - 1 && i < grid.size() - 1 &&
             grid[i + 1][j + 1] == '@') +
            // E
            (j < grid[0].size() - 1 && grid[i][j + 1] == '@') +
            // NE  ← missing one
            (i >= 1 && j < grid[0].size() - 1 && grid[i - 1][j + 1] == '@');
        if (cnt < 4) {
          final_ans++;
          positions.push_back({i, j});
        }
      }
    }
    for (const auto [i, j] : positions)
      grid[i][j] = '.';
  } while (positions.size() != 0);
```

# Conclusion

These might not have been the most efficient solutions, but they are surely simple, and that also counts in software engineering. Most of the times, simplicity of the solutions matters mote than the premature optimizations/optimizations possible.

Signing off
