Skip to content

Commit d358221

Browse files
committed
2024/15
1 parent e18f390 commit d358221

File tree

2 files changed

+18
-7
lines changed

2 files changed

+18
-7
lines changed

2024/Day15/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,14 @@ You appear back inside your own mini submarine! Each Historian drives their mini
44
You look up to see a vast school of [lanternfish](/2021/day/6) swimming past you. On closer inspection, they seem quite anxious, so you drive your mini submarine over to see if you can help.
55

66
_Visit the website for the full story and [full puzzle](https://adventofcode.com/2024/day/15) description._
7+
8+
Here’s a revised version with improved grammar, clarity, and flow:
9+
10+
11+
A nice Sokoban-style puzzle for the weekend! The main difference is that in the original Sokoban, the robot could push only a single box, not multiple boxes. This adds complexity to both parts of the puzzle. However, it’s not that difficult to handle... I moved the hard parts into the `TryToStep` function that takes the map, a position, and a direction, then attempts to make a move in that direction.
12+
13+
If the position corresponds to the robot or a box, the function checks whether the neighboring cell is free or can be made free by pushing boxes in the given direction. The .NET API sometimes uses the `TryToDoX` pattern, where a function returns a boolean result and provides an `out` parameter. I reused this pattern here. On success, the updated map is returned via the `ref` parameter. If the move fails, the map remains unchanged.
14+
15+
The real challenge lies in `part 2`, where recursion needs to branch whenever the robot pushes more than one box at a time. In such cases, we must invoke `TryToStep` for each box. Due to the recursive nature of the algorithm, it’s possible for one branch to succeed while the other fails. When this happens, the entire map must be reset to its original state before we pop from the recursion. This could be quite tricky to manage unless you make copies of the dictionary that holds the state — or, as I did, use an immutable dictionary instead.
16+
17+
I’m not entirely satisfied with the "if-ladder" structure of the `TryToStep` function, but for now, I don’t have a better idea to handle all the cases in a more readable way.

2024/Day15/Solution.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public double Solve(string input) {
2424

2525
var robot = map.Keys.Single(k => map[k] == '@');
2626
foreach (var dir in steps) {
27-
if (Step(ref map, robot, dir)) {
27+
if (TryToStep(ref map, robot, dir)) {
2828
robot += dir;
2929
}
3030
}
@@ -37,39 +37,39 @@ public double Solve(string input) {
3737
// Attempts to move the robot in the given direction on the map, pushing boxes as necessary.
3838
// If the move is successful, the map is updated to reflect the new positions and the function returns true.
3939
// Otherwise, the map remains unchanged and the function returns false.
40-
bool Step(ref Map map, Complex pos, Complex dir) {
40+
bool TryToStep(ref Map map, Complex pos, Complex dir) {
4141
var mapOrig = map;
4242

4343
if (map[pos] == '.') {
4444
return true;
4545
} else if (map[pos] == 'O' || map[pos] == '@') {
46-
if (Step(ref map, pos + dir, dir)) {
46+
if (TryToStep(ref map, pos + dir, dir)) {
4747
map = map
4848
.SetItem(pos + dir, map[pos])
4949
.SetItem(pos, '.');
5050
return true;
5151
}
5252
} else if (map[pos] == ']') {
53-
return Step(ref map, pos + Left, dir);
53+
return TryToStep(ref map, pos + Left, dir);
5454
} else if (map[pos] == '[') {
5555
if (dir == Left) {
56-
if (Step(ref map, pos + Left, Left)) {
56+
if (TryToStep(ref map, pos + Left, dir)) {
5757
map = map
5858
.SetItem(pos + Left, '[')
5959
.SetItem(pos, ']')
6060
.SetItem(pos + Right, '.');
6161
return true;
6262
}
6363
} else if (dir == Right) {
64-
if (Step(ref map, pos + 2 * Right, dir)) {
64+
if (TryToStep(ref map, pos + 2 * Right, dir)) {
6565
map = map
6666
.SetItem(pos, '.')
6767
.SetItem(pos + Right, '[')
6868
.SetItem(pos + 2 * Right, ']');
6969
return true;
7070
}
7171
} else {
72-
if (Step(ref map, pos + dir, dir) && Step(ref map, pos + Right + dir, dir)) {
72+
if (TryToStep(ref map, pos + dir, dir) && TryToStep(ref map, pos + Right + dir, dir)) {
7373
map = map
7474
.SetItem(pos, '.')
7575
.SetItem(pos + Right, '.')

0 commit comments

Comments
 (0)