4
4
"aoc-shared/pkg/sharedcode"
5
5
"aoc-shared/pkg/sharedstruct"
6
6
"fmt"
7
+ "math"
7
8
"os"
8
9
"path/filepath"
9
10
"runtime"
@@ -34,70 +35,123 @@ func main() {
34
35
35
36
func partOne (contents []string ) {
36
37
grid := parseToGrid (contents )
38
+ distancesToPoint := make ([][]int , len (grid ))
39
+ for i := 0 ; i < len (grid ); i ++ {
40
+ distancesToPoint [i ] = make ([]int , len (grid [i ]))
41
+ for j := 0 ; j < len (grid [i ]); j ++ {
42
+ distancesToPoint [i ][j ] = - 1
43
+ }
44
+ }
45
+
37
46
start , end := findStartAndEnd (contents )
38
- numSeconds := bfs ( grid , start , end )
39
- savedSecondsCount := make ( map [ int ] int , 0 )
47
+ distancesToPoint [ start [ 0 ]][ start [ 1 ]] = 0
48
+ bfsDetermineDistances ( grid , start , end , & distancesToPoint )
40
49
41
- displayGrid ( grid )
50
+ count := 0
42
51
43
- // We'll go through all options of removals. If they can remove just 1, or 1&2 or 2, is this 3 options??
44
- // We might need to avoid wasting time and duplicating, 1,2 != 2,1?? Will try without first
45
- for i := 1 ; i < len (grid )- 2 ; i ++ {
46
- for j := 1 ; j < len (grid [i ])- 1 ; j ++ {
47
- nextMustBeHash := false
48
- if grid [i ][j ] == 'E' || grid [i ][j ] == 'S' {
49
- continue
50
- }
51
- if grid [i ][j ] != '#' {
52
+ // To avoid double counting, we only look at half the points per space;
53
+ halfDistances := [4 ][2 ]int {
54
+ {2 , 0 },
55
+ {1 , 1 },
56
+ {0 , 2 },
57
+ {- 1 , 1 },
58
+ }
59
+
60
+ picoSecondsToSave := 100
61
+ if isUsingExample {
62
+ picoSecondsToSave = 40 // Expect 2 as the output
63
+ }
64
+
65
+ for i := 0 ; i < len (grid ); i ++ {
66
+ for j := 0 ; j < len (grid [i ]); j ++ {
67
+ if distancesToPoint [i ][j ] == - 1 {
52
68
continue
53
- // // Go 4 directions and only valid if it is a #
54
- // nextMustBeHash = true
55
69
}
56
70
57
- for _ , dir := range directions {
71
+ for _ , dir := range halfDistances {
58
72
newI := i + dir [0 ]
59
73
newJ := j + dir [1 ]
60
74
61
75
// Out of bounds checks
62
- if newI < 0 || newJ < 0 || newI > len (grid )- 1 || newJ > len (grid [i ])- 1 {
76
+ if newI < 0 || newJ < 0 || newI > len (grid )- 1 || newJ > len (grid [0 ])- 1 {
63
77
continue
64
78
}
65
79
66
- // Can't finish on an out of bounds tile!
67
80
if grid [newI ][newJ ] == '#' {
68
81
continue
69
82
}
70
83
71
- if nextMustBeHash && grid [newI ][newJ ] != '#' {
72
- // Would not be a cheat, so skip!
73
- continue
84
+ if int (math .Abs (float64 (distancesToPoint [i ][j ]- distancesToPoint [newI ][newJ ]))) >= picoSecondsToSave + 2 {
85
+ count ++
74
86
}
87
+ }
75
88
76
- newGrid := cloneGrid (grid )
77
- newGrid [i ][j ] = '.'
78
- if grid [newI ][newJ ] != 'E' && grid [newI ][newJ ] != 'S' {
79
- newGrid [newI ][newJ ] = '.'
80
- }
89
+ }
90
+ }
91
+
92
+ sharedstruct .PrintOutput (sharedstruct.Output {
93
+ Day : 20 ,
94
+ Part : 1 ,
95
+ Value : count ,
96
+ })
97
+ }
98
+
99
+ func partTwo (contents []string ) {
100
+ grid := parseToGrid (contents )
101
+ distancesToPoint := make ([][]int , len (grid ))
102
+ for i := 0 ; i < len (grid ); i ++ {
103
+ distancesToPoint [i ] = make ([]int , len (grid [i ]))
104
+ for j := 0 ; j < len (grid [i ]); j ++ {
105
+ distancesToPoint [i ][j ] = - 1
106
+ }
107
+ }
108
+
109
+ start , end := findStartAndEnd (contents )
110
+ distancesToPoint [start [0 ]][start [1 ]] = 0
111
+ bfsDetermineDistances (grid , start , end , & distancesToPoint )
81
112
82
- seconds := bfs (newGrid , start , end )
83
- // Took 100s, now takes 55s. So saved 100-55=45 seconds
84
- savedSeconds := numSeconds - seconds
85
- if savedSeconds > 0 {
86
- if savedSeconds == 64 {
87
- fmt .Println ()
88
- displayGrid (newGrid )
89
- fmt .Println ("debug" )
113
+ count := 0
114
+
115
+ picoSecondsToSave := 100
116
+
117
+ visited := make (map [[2 ][2 ]int ]bool , 0 ) // start and end
118
+
119
+ for i := 0 ; i < len (grid ); i ++ {
120
+ for j := 0 ; j < len (grid [i ]); j ++ {
121
+ for radius := 2 ; radius < 21 ; radius ++ {
122
+ for di := 0 ; di < radius + 1 ; di ++ {
123
+ dj := radius - di
124
+ for _ , dir := range [4 ][2 ]int {{i + di , j + dj }, {i + di , j - dj }, {i - di , j + dj }, {i - di , j - dj }} {
125
+ newI := dir [0 ]
126
+ newJ := dir [1 ]
127
+ if _ , ok := visited [[2 ][2 ]int {{i , j }, {newI , newJ }}]; ok {
128
+ continue
129
+ }
130
+
131
+ visited [[2 ][2 ]int {{i , j }, {newI , newJ }}] = true
132
+
133
+ // Out of bounds checks
134
+ if newI < 0 || newJ < 0 || newI > len (grid )- 1 || newJ > len (grid [0 ])- 1 {
135
+ continue
136
+ }
137
+
138
+ if grid [newI ][newJ ] == '#' {
139
+ continue
140
+ }
141
+
142
+ if distancesToPoint [i ][j ]- distancesToPoint [newI ][newJ ] >= picoSecondsToSave + radius {
143
+ count ++
144
+ }
90
145
}
91
- savedSecondsCount [savedSeconds ]++
92
146
}
93
147
}
148
+
94
149
}
95
150
}
96
-
97
151
sharedstruct .PrintOutput (sharedstruct.Output {
98
152
Day : 20 ,
99
- Part : 1 ,
100
- Value : savedSecondsCount ,
153
+ Part : 2 ,
154
+ Value : count ,
101
155
})
102
156
}
103
157
@@ -113,10 +167,8 @@ type queueStruct struct {
113
167
steps int
114
168
}
115
169
116
- func bfs (grid [][]byte , start [2 ]int , end [2 ]int ) int {
117
- // BFS now!
170
+ func bfsDetermineDistances (grid [][]byte , start [2 ]int , end [2 ]int , distancesToPoint * [][]int ) int {
118
171
queue := make ([]queueStruct , 0 )
119
- visited := make (map [[2 ]int ]bool )
120
172
121
173
queue = append (queue , queueStruct {
122
174
pos : start ,
@@ -132,18 +184,6 @@ func bfs(grid [][]byte, start [2]int, end [2]int) int {
132
184
// Grab the next element in queue
133
185
element , queue = queue [0 ], queue [1 :]
134
186
135
- // if visited, skip
136
- _ , ok := visited [element .pos ]
137
- if ok {
138
- continue
139
- }
140
-
141
- if element .pos == end {
142
- return element .steps
143
- }
144
-
145
- visited [element .pos ] = true
146
-
147
187
for _ , dir := range directions {
148
188
newI := element .pos [0 ] + dir [0 ]
149
189
newJ := element .pos [1 ] + dir [1 ]
@@ -157,6 +197,12 @@ func bfs(grid [][]byte, start [2]int, end [2]int) int {
157
197
continue
158
198
}
159
199
200
+ if (* distancesToPoint )[newI ][newJ ] != - 1 {
201
+ continue
202
+ }
203
+
204
+ (* distancesToPoint )[newI ][newJ ] = (* distancesToPoint )[element .pos [0 ]][element .pos [1 ]] + 1
205
+
160
206
queue = append (queue , queueStruct {
161
207
pos : [2 ]int {newI , newJ },
162
208
steps : element .steps + 1 ,
@@ -167,14 +213,6 @@ func bfs(grid [][]byte, start [2]int, end [2]int) int {
167
213
return - 1
168
214
}
169
215
170
- func partTwo (contents []string ) {
171
- sharedstruct .PrintOutput (sharedstruct.Output {
172
- Day : 20 ,
173
- Part : 2 ,
174
- Value : "TODO" ,
175
- })
176
- }
177
-
178
216
func findStartAndEnd (contents []string ) ([2 ]int , [2 ]int ) {
179
217
var start , end [2 ]int
180
218
foundCount := 0
0 commit comments