This repository has been archived by the owner on Dec 28, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
27179eb
commit 49e4f16
Showing
4 changed files
with
175 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,104 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"github.com/terminalnode/adventofcode2024/common" | ||
"github.com/terminalnode/adventofcode2024/common/util" | ||
"slices" | ||
) | ||
|
||
func main() { | ||
common.Setup(20, nil, nil) | ||
common.Setup(20, part1, nil) | ||
} | ||
|
||
func part1( | ||
input string, | ||
) string { | ||
p, err := parse(input) | ||
if err != nil { | ||
return fmt.Sprintf("Failed to parse input: %v", err) | ||
} | ||
|
||
dm, path, err := p.createDistanceMap() | ||
if err != nil { | ||
return fmt.Sprintf("Failed to create distance map: %v", err) | ||
} | ||
|
||
cheatCounts := make(map[int]int) | ||
for _, pos := range path { | ||
distance := dm[pos.Y][pos.X] | ||
next := []util.Coordinate{ | ||
pos.North().North(), | ||
pos.South().South(), | ||
pos.East().East(), | ||
pos.West().West(), | ||
} | ||
|
||
for _, nPos := range next { | ||
// Normally moving two steps should give us two less distance, | ||
// so these 2 are subtracted from the saved amount. | ||
nDistance := dm[nPos.Y][nPos.X] | ||
saved := nDistance - distance - 2 | ||
if saved > 0 { | ||
cheatCounts[saved] += 1 | ||
} | ||
} | ||
} | ||
|
||
count := 0 | ||
for k, v := range cheatCounts { | ||
if k >= 100 { | ||
count += v | ||
} | ||
fmt.Printf("There are %d cheats that save %d picoseconds.\n", v, k) | ||
} | ||
|
||
return fmt.Sprintf("Number of cheats saving at least 100ps: %d", count) | ||
} | ||
|
||
func (p parsedInput) createDistanceMap() (distanceMap, []util.Coordinate, error) { | ||
newM := make(distanceMap) | ||
path := make([]util.Coordinate, 0, p.length) | ||
for y, _ := range p.m { | ||
newM[y] = make(map[intX]int) | ||
} | ||
|
||
distance := 0 | ||
curr := util.Coordinate{X: p.e.X, Y: p.e.Y} | ||
newM[curr.Y][curr.X] = 0 | ||
|
||
visited := make(map[intY]map[intX]bool) | ||
for y := range p.m { | ||
visited[y] = make(map[intX]bool) | ||
} | ||
visited[curr.Y][curr.X] = true | ||
|
||
for !curr.Equals(p.s) { | ||
distance++ | ||
found := false | ||
for _, newP := range curr.Adjacent4() { | ||
isBlocked := !p.m[newP.Y][newP.X] | ||
isVisited := visited[newP.Y][newP.X] | ||
if isBlocked || isVisited { | ||
continue | ||
} | ||
|
||
found = true | ||
newM[newP.Y][newP.X] = distance | ||
path = append(path, newP) | ||
visited[newP.Y][newP.X] = true | ||
curr = newP | ||
break | ||
} | ||
|
||
if !found { | ||
return newM, path, fmt.Errorf("missing path from %v", curr) | ||
} | ||
} | ||
|
||
// Skip end position and position next to end position, | ||
// because there's no point in cheating there. | ||
slices.Reverse(path[1:]) | ||
|
||
return newM, path, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"github.com/terminalnode/adventofcode2024/common/util" | ||
"strings" | ||
) | ||
|
||
type intX = int | ||
type intY = int | ||
type raceMap map[intY]map[intX]bool | ||
type distanceMap map[intY]map[intX]int | ||
|
||
type parsedInput struct { | ||
m raceMap | ||
length int | ||
s util.Coordinate | ||
e util.Coordinate | ||
} | ||
|
||
func parse( | ||
input string, | ||
) (parsedInput, error) { | ||
lines := strings.Split(input, "\n") | ||
m := make(raceMap) | ||
length := 0 | ||
s := util.Coordinate{} | ||
e := util.Coordinate{} | ||
sFound := false | ||
eFound := false | ||
|
||
for y, line := range lines { | ||
m[y] = make(map[intX]bool) | ||
for x, ch := range line { | ||
if ch == '#' { | ||
continue | ||
} | ||
length += 1 | ||
|
||
if ch == 'S' { | ||
sFound = true | ||
s = util.Coordinate{X: x, Y: y} | ||
} else if ch == 'E' { | ||
eFound = true | ||
e = util.Coordinate{X: x, Y: y} | ||
} | ||
m[y][x] = true | ||
} | ||
} | ||
out := parsedInput{m: m, s: s, e: e, length: length} | ||
|
||
if !sFound && !eFound { | ||
return out, errors.New("neither start nor end found") | ||
} else if !sFound { | ||
return out, errors.New("no start found") | ||
} else if !eFound { | ||
return out, errors.New("no end found") | ||
} | ||
|
||
return out, nil | ||
} |