@@ -91,60 +91,72 @@ type cheat struct {
91
91
end util.Point
92
92
}
93
93
94
- func findCheats (course [][]byte , moves []util.Point , startIdx int , minSaving int , cheatedWalls map [util. Point ]util. Void ) []cheat {
94
+ func findCheats (course [][]byte , moves []util.Point , startIdx int , minSaving int , debug bool ) []cheat {
95
95
var s = moves [startIdx ]
96
96
var cheats []cheat
97
- for _ , d := range directions {
98
- var w = s .Add (d )
99
- if ! w .IsInBounds (len (course ), len (course [w .Y ])) {
100
- continue
101
- }
102
- if course [w.Y ][w.X ] != WALL {
103
- continue
104
- }
105
- var e = w .Add (d )
106
- var ei = findMoveIdx (moves , e )
107
- // HINT: save 100 picoseconds, but this includes two additional steps
108
- if ei - startIdx < minSaving + 2 {
109
- // TODO: might there be multiple cheats forward?
110
- continue
97
+ var visited = make (map [util.Point ]int )
98
+ var recents = make (map [util.Point ]int )
99
+ recents [s ] = 0
100
+ for len (recents ) > 0 {
101
+ var found = make (map [util.Point ]int )
102
+ for p1 , cost := range recents {
103
+ for _ , d := range directions {
104
+ var p2 = p1 .Add (d )
105
+ if ! p2 .IsInBounds (len (course ), len (course [p1 .Y ])) {
106
+ continue
107
+ }
108
+ if _ , ok := visited [p2 ]; ok {
109
+ continue
110
+ }
111
+ if course [p2.Y ][p2.X ] == WALL {
112
+ visited [p2 ] = cost + 1
113
+ found [p2 ] = cost + 1
114
+ continue
115
+ }
116
+ var endIdx = findMoveIdx (moves , p2 )
117
+ var saving = endIdx - startIdx - cost - 1
118
+ if saving < minSaving {
119
+ continue
120
+ }
121
+ if debug {
122
+ fmt .Printf ("%d picoseconds saved by cheat: %d,%d -> %d,%d\n " , saving , s .Y , s .X , p2 .Y , p2 .X )
123
+ }
124
+ cheats = append (cheats , cheat {start : s , end : p2 })
125
+ }
111
126
}
112
- cheatedWalls [w ] = util.Void {}
113
- fmt .Printf ("%d picoseconds saved by cheat: %d,%d -> %d,%d\n " , ei - startIdx - 2 , s .Y , s .X , e .Y , e .X )
114
- cheats = append (cheats , cheat {start : s , end : e })
127
+ recents = found
115
128
}
116
- return cheats
117
- }
118
-
119
- func printCourseWithCheats (course [][]byte , cheats map [util.Point ]util.Void ) {
120
- for y := range course {
121
- for x := range course [y ] {
122
- if _ , ok := cheats [util.Point {Y : y , X : x }]; ok {
123
- fmt .Print ("C" )
124
- } else {
125
- fmt .Print (string (course [y ][x ]))
129
+ if debug {
130
+ for y := range course {
131
+ for x := range course [y ] {
132
+ if cost , ok := visited [util.Point {Y : y , X : x }]; ok {
133
+ fmt .Print (cost % 10 )
134
+ } else {
135
+ fmt .Print (string (course [y ][x ]))
136
+ }
126
137
}
138
+ fmt .Println ()
127
139
}
128
140
fmt .Println ()
129
141
}
130
- fmt . Println ()
142
+ return cheats
131
143
}
132
144
133
145
func main () {
134
146
var minSaving = flag .Int ("minSaving" , 100 , "consider cheats that save at least minSaving picoseconds" )
147
+ var debug = flag .Bool ("debug" , false , "verbose output" )
135
148
flag .Parse ()
136
149
137
150
var course = readCourse ()
138
151
var moves = findMoves (course )
139
152
var time = len (moves ) - 1
140
153
fmt .Printf ("course takes %d picoseconds\n " , time )
141
154
var cheats = make (map [cheat ]util.Void )
142
- var cheatedWalls = make (map [util.Point ]util.Void )
143
155
for i := range moves {
144
- for _ , c := range findCheats (course , moves , i , * minSaving , cheatedWalls ) {
156
+ for _ , c := range findCheats (course , moves , i , * minSaving , * debug ) {
145
157
cheats [c ] = util.Void {}
146
158
}
159
+ fmt .Printf ("searched cheats for %d/%d moves\n " , i + 1 , len (moves ))
147
160
}
148
- printCourseWithCheats (course , cheatedWalls )
149
161
fmt .Printf ("found %d unique cheats saving >= %d picoseconds" , len (cheats ), * minSaving )
150
162
}
0 commit comments