@@ -8,11 +8,16 @@ import (
8
8
)
9
9
10
10
func main () {
11
- common .Setup (20 , part1 , nil )
11
+ common .Setup (20 , part1 , part2 )
12
12
}
13
13
14
- func part1 (
14
+ func part1 (input string ) string { return solve (input , 2 , 100 ) }
15
+ func part2 (input string ) string { return solve (input , 20 , 100 ) }
16
+
17
+ func solve (
15
18
input string ,
19
+ steps int ,
20
+ limit int ,
16
21
) string {
17
22
p , err := parse (input )
18
23
if err != nil {
@@ -26,24 +31,25 @@ func part1(
26
31
27
32
cheatCounts := make (map [int ]int )
28
33
for _ , pos := range path {
29
- for k , v := range findAllCheats (dm , pos , 2 ) {
34
+ for k , v := range findAllCheats (dm , pos , p . e , steps ) {
30
35
cheatCounts [k ] += v
31
36
}
32
37
}
33
38
34
39
count := 0
35
40
for k , v := range cheatCounts {
36
- if k >= 100 {
41
+ if k >= limit {
37
42
count += v
38
43
}
39
44
}
40
45
41
- return fmt .Sprintf ("Number of cheats saving at least 100ps : %d" , count )
46
+ return fmt .Sprintf ("Number of cheats saving at least %d ps : %d" , limit , count )
42
47
}
43
48
44
49
func findAllCheats (
45
50
dm distanceMap ,
46
51
pos util.Coordinate ,
52
+ ePos util.Coordinate ,
47
53
steps int ,
48
54
) map [int ]int {
49
55
// Initialize visited set
@@ -53,36 +59,23 @@ func findAllCheats(
53
59
}
54
60
55
61
cheats := make (map [int ]int )
56
- positions := pos .Adjacent4 ()
57
62
distance := dm [pos.Y ][pos.X ]
58
- for step := 1 ; step <= steps ; step ++ {
59
- newPositions := make ([]util.Coordinate , 0 , 4 * len (positions ))
60
- for _ , p := range positions {
61
- // 1. Check if in visited set, if it is then skip.
62
- if visited [p.Y ][p.X ] || visited [p .Y ] == nil {
63
- continue
63
+ for step := 2 ; step <= steps ; step ++ {
64
+ for y := - step ; y <= step ; y ++ {
65
+ remainingSteps := step - util .AbsInt (y )
66
+ for x := - remainingSteps ; x <= remainingSteps ; x ++ {
67
+ if util .AbsInt (x )+ util .AbsInt (y ) != step {
68
+ continue
69
+ }
70
+ nPos := util.Coordinate {X : pos .X + x , Y : pos .Y + y }
71
+
72
+ nDistance := dm [nPos.Y ][nPos.X ]
73
+ saved := distance - nDistance - step
74
+ if (nDistance != 0 || nPos .Equals (ePos )) && saved > 0 {
75
+ cheats [saved ] += 1
76
+ }
64
77
}
65
- visited [p.Y ][p.X ] = true
66
-
67
- // 2. Calculate time saved
68
- // Moving here normally will take $step number of steps, so savings
69
- // are calculated by subtracting step from the distance map.
70
- nDistance := dm [p.Y ][p.X ]
71
- saved := nDistance - distance - step
72
-
73
- if nDistance != 0 && saved <= 0 {
74
- // 3. If we didn't save time by going this way, continue.
75
- continue
76
- } else if nDistance != 0 {
77
- // 4. We didn't save time by going here, but we're still in the wilderness
78
- cheats [saved ] += 1
79
- }
80
-
81
- // 5. This position is not trash, lets add all it's neighbors to the new positions set
82
- newPositions = append (newPositions , p .Adjacent4 ()... )
83
78
}
84
-
85
- positions = newPositions
86
79
}
87
80
88
81
return cheats
0 commit comments