add day-18 + benchmarks

This commit is contained in:
2024-12-18 18:48:11 +00:00
parent 6cb3fd1654
commit 9d7a9d5791
23 changed files with 658 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
goos: linux
goarch: amd64
pkg: github.com/onyx-and-iris/aoc2024/day-18/internal/one
cpu: Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz
BenchmarkSolve-12 1000000000 0.004050 ns/op
ok github.com/onyx-and-iris/aoc2024/day-18/internal/one 0.029s

View File

@@ -0,0 +1,50 @@
package one
import (
"slices"
"strings"
)
type graph struct {
start Point
end Point
data []string
}
func newGraph(width, height, numCorruptions int, corruptedCoords [][]int) *graph {
var data []string
var sb strings.Builder
for range height {
for range width {
sb.WriteRune('.')
}
data = append(data, sb.String())
sb.Reset()
}
for _, coords := range corruptedCoords[:numCorruptions] {
data[coords[1]] = replaceAtIndex(data[coords[1]], '#', coords[0])
}
return &graph{Point{0, 0}, Point{len(data[0]) - 1, len(data) - 1}, data}
}
func (g *graph) String() string {
return strings.Join(g.data, "\n")
}
func (g *graph) isOutOfBounds(p Point) bool {
return p.X < 0 || p.Y < 0 || p.Y >= len(g.data) || p.X >= len(g.data[p.Y])
}
func (g *graph) valueAt(p Point) rune {
return rune(g.data[p.Y][p.X])
}
func (g *graph) debug(path []Point) string {
temp := slices.Clone(g.data)
for _, p := range path {
temp[p.Y] = replaceAtIndex(temp[p.Y], 'O', p.X)
}
return strings.Join(temp, "\n")
}

View File

@@ -0,0 +1,10 @@
package one
func neighbours(p Point) [4]Point {
return [4]Point{
{p.X, p.Y - 1}, // N
{p.X + 1, p.Y}, // E
{p.X, p.Y + 1}, // S
{p.X - 1, p.Y}, // W
}
}

View File

@@ -0,0 +1,6 @@
package one
type Point struct {
X int
Y int
}

View File

@@ -0,0 +1,76 @@
package one
import (
"bytes"
"math"
"github.com/onyx-and-iris/aoc2024/day-18/internal/config"
"github.com/onyx-and-iris/aoc2024/day-18/internal/queue"
log "github.com/sirupsen/logrus"
)
var ShortestPath []Point
func Solve(buf []byte, config config.Config) (int, error) {
r := bytes.NewReader(buf)
graph, err := parseLines(r, config)
if err != nil {
return 0, err
}
log.Debugf("start: %v end: %v", graph.start, graph.end)
log.Debugf("\n%s\n", graph.String())
queue := queue.New[Point]()
queue.Enqueue(graph.start)
visited := make(map[Point]struct{})
costs := make(map[Point]int)
prev := make(map[Point]Point)
for !queue.IsEmpty() {
current := queue.Dequeue()
if current == graph.end {
break
}
_, ok := visited[current]
if ok {
continue
}
visited[current] = struct{}{}
for _, n := range neighbours(current) {
if graph.isOutOfBounds(n) {
continue
}
if graph.valueAt(n) == '#' {
continue
}
_, ok := costs[n]
if !ok {
costs[n] = math.MaxInt
}
new_cost := costs[current] + 1
if new_cost < costs[n] {
costs[n] = new_cost
prev[n] = current
queue.Enqueue(n)
}
}
}
ShortestPath = []Point{graph.end}
node := prev[graph.end]
for node != graph.start {
ShortestPath = append(ShortestPath, prev[node])
node = prev[node]
}
log.Debugf("\n%s\n", graph.debug(ShortestPath))
return len(ShortestPath), nil
}

View File

@@ -0,0 +1,21 @@
package one
import (
_ "embed"
"os"
"testing"
"github.com/onyx-and-iris/aoc2024/day-18/internal/config"
)
//go:embed testdata/input.txt
var data []byte
func BenchmarkSolve(b *testing.B) {
os.Stdout, _ = os.Open(os.DevNull)
Solve(data, config.Config{
Width: 71,
Height: 71,
NumCorruptions: 1024,
})
}

View File

@@ -0,0 +1,41 @@
package one
import (
"bufio"
"io"
"strconv"
"strings"
"github.com/onyx-and-iris/aoc2024/day-18/internal/config"
)
func parseLines(r io.Reader, config config.Config) (*graph, error) {
corruptedCoords := [][]int{}
scanner := bufio.NewScanner(r)
for scanner.Scan() {
corruptedCoords = append(corruptedCoords, func() []int {
x := strings.Split(scanner.Text(), ",")
return []int{mustConv(x[0]), mustConv(x[1])}
}())
}
if err := scanner.Err(); err != nil {
return nil, err
}
return newGraph(config.Width, config.Height, config.NumCorruptions, corruptedCoords), nil
}
func mustConv(s string) int {
n, err := strconv.Atoi(s)
if err != nil {
panic(err)
}
return n
}
func replaceAtIndex(s string, r rune, i int) string {
out := []rune(s)
out[i] = r
return string(out)
}