1
1
package main
2
2
3
3
import (
4
+ "errors"
4
5
"fmt"
5
6
"github.com/terminalnode/adventofcode2024/common"
6
7
"github.com/terminalnode/adventofcode2024/common/util"
7
8
)
8
9
9
- func main () {
10
- common .Setup (15 , part1 , nil )
11
- }
10
+ func main () { common .Setup (15 , part1 , part2 ) }
11
+ func part1 (input string ) string { return solve (input , false ) }
12
+ func part2 (input string ) string { return solve (input , true ) }
13
+
14
+ type visitedSet = map [int ]map [int ]bool
12
15
13
- func part1 (
16
+ func solve (
14
17
input string ,
18
+ makeWide bool ,
15
19
) string {
16
- p , err := parse (input , false )
20
+ p , err := parse (input , makeWide )
17
21
if err != nil {
18
22
return fmt .Sprintf ("Failed to parse input: %v" , err )
19
23
}
20
24
21
25
for _ , move := range p .moves {
22
- endPosition , err := findEndPosition (p .warehouse , p .robot , move )
26
+ newPos := move (p .robot )
27
+ boxMoves , err := getBoxMoves (p .warehouse , newPos , move , make (visitedSet ))
23
28
if err != nil {
24
29
continue
25
30
}
26
31
27
- newRobot := move (p .robot )
28
- if ! newRobot .Equals (endPosition ) {
29
- // End position is more than one step, meaning we need to move boxes
30
- p.warehouse [newRobot.Y ][newRobot.X ] = Ground
31
- p.warehouse [endPosition.Y ][endPosition.X ] = Box
32
+ // Zero out all moves
33
+ for _ , bm := range boxMoves {
34
+ c := bm .curr
35
+ p.warehouse [c.Y ][c.X ] = Ground
36
+ }
37
+
38
+ // Put all boxes in their new positions
39
+ for _ , bm := range boxMoves {
40
+ c := bm .new
41
+ p.warehouse [c.Y ][c.X ] = bm .ch
32
42
}
33
- p .robot = newRobot
43
+
44
+ p .robot = newPos
34
45
}
35
46
47
+ if makeWide {
48
+ return fmt .Sprintf ("Sum of all GPS coordinates in the wide area: %d" , score (p .warehouse ))
49
+ }
36
50
return fmt .Sprintf ("Sum of all GPS coordinates: %d" , score (p .warehouse ))
37
51
}
38
52
39
- func findEndPosition (
53
+ type boxMove struct {
54
+ ch int32
55
+ curr util.Coordinate
56
+ new util.Coordinate
57
+ }
58
+
59
+ func getBoxMoves (
40
60
w warehouseMatrix ,
41
- s util.Coordinate ,
61
+ start util.Coordinate ,
42
62
d util.Direction ,
43
- ) (util.Coordinate , error ) {
44
- np := d (s )
45
- ch := w [np.Y ][np.X ]
46
- switch ch {
47
- case Ground :
48
- return np , nil
49
- case Box :
50
- return findEndPosition (w , np , d )
51
- case Wall :
52
- return np , fmt .Errorf ("wall hit" )
63
+ set visitedSet ,
64
+ ) ([]boxMove , error ) {
65
+ if inVisitedSet (set , start ) {
66
+ return []boxMove {}, nil
67
+ }
68
+ set [start.X ][start.Y ] = true
69
+
70
+ // Initializations, boxMoves capacity is just a guess
71
+ boxMoves := make ([]boxMove , 0 , 200 )
72
+ ch := w [start.Y ][start.X ]
73
+
74
+ // Early returns on ground and wall
75
+ if ch == Ground {
76
+ return boxMoves , nil
77
+ } else if ch == Wall {
78
+ return boxMoves , errors .New ("wall hit" )
53
79
}
54
80
55
- panic (fmt .Sprintf ("Invalid character: %c" , ch ))
81
+ // Whatever happens, add this move to the list
82
+ newPos := d (start )
83
+ boxMoves = append (boxMoves , boxMove {ch : ch , curr : start , new : newPos })
84
+
85
+ // Get next moves and add to the list
86
+ next , err := getBoxMoves (w , newPos , d , set )
87
+ if err != nil {
88
+ return boxMoves , err
89
+ }
90
+ boxMoves = append (boxMoves , next ... )
91
+
92
+ // Now do the same thing for the partner boxes, if any
93
+ if ch != Box {
94
+ if ch == LeftBox {
95
+ next , err = getBoxMoves (w , start .East (), d , set )
96
+ } else if ch == RightBox {
97
+ next , err = getBoxMoves (w , start .West (), d , set )
98
+ }
99
+ if err != nil {
100
+ return boxMoves , err
101
+ }
102
+ boxMoves = append (boxMoves , next ... )
103
+ }
104
+
105
+ return boxMoves , err
106
+ }
107
+
108
+ func inVisitedSet (
109
+ set visitedSet ,
110
+ c util.Coordinate ,
111
+ ) bool {
112
+ if set [c .X ] == nil {
113
+ set [c .X ] = make (map [int ]bool )
114
+ }
115
+ return set [c.X ][c.Y ]
56
116
}
57
117
58
118
func score (
@@ -61,7 +121,7 @@ func score(
61
121
sum := 0
62
122
for y , row := range wh {
63
123
for x , ch := range row {
64
- if ch != Box {
124
+ if ch != Box && ch != LeftBox {
65
125
continue
66
126
}
67
127
sum += x + 100 * y
0 commit comments