@@ -91,60 +91,72 @@ type cheat struct {
9191 end util.Point
9292}
9393
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 {
9595 var s = moves [startIdx ]
9696 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+ }
111126 }
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
115128 }
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+ }
126137 }
138+ fmt .Println ()
127139 }
128140 fmt .Println ()
129141 }
130- fmt . Println ()
142+ return cheats
131143}
132144
133145func main () {
134146 var minSaving = flag .Int ("minSaving" , 100 , "consider cheats that save at least minSaving picoseconds" )
147+ var debug = flag .Bool ("debug" , false , "verbose output" )
135148 flag .Parse ()
136149
137150 var course = readCourse ()
138151 var moves = findMoves (course )
139152 var time = len (moves ) - 1
140153 fmt .Printf ("course takes %d picoseconds\n " , time )
141154 var cheats = make (map [cheat ]util.Void )
142- var cheatedWalls = make (map [util.Point ]util.Void )
143155 for i := range moves {
144- for _ , c := range findCheats (course , moves , i , * minSaving , cheatedWalls ) {
156+ for _ , c := range findCheats (course , moves , i , * minSaving , * debug ) {
145157 cheats [c ] = util.Void {}
146158 }
159+ fmt .Printf ("searched cheats for %d/%d moves\n " , i + 1 , len (moves ))
147160 }
148- printCourseWithCheats (course , cheatedWalls )
149161 fmt .Printf ("found %d unique cheats saving >= %d picoseconds" , len (cheats ), * minSaving )
150162}
0 commit comments