adventofcode/2024/day18/main.go

114 lines
2.2 KiB
Go

package main
import (
"fmt"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
func main() {
inp := h.StdinToStringSlice()
// size, bytes := 6, 12 // Test Input
size, bytes := 70, 1024 // Actual Input
part1(inp, size, bytes)
fmt.Println()
part2(inp, size, bytes)
}
func part1(inp []string, size, bytes int) {
// bytes:= 12 // Test Input
m := h.NewCoordByteMap()
m.BRX, m.BRY = size, size
drops := parseInput(inp)
for i := 0; i < bytes; i++ {
m.Put(drops[i], '#')
}
fmt.Println("# Part 1")
fmt.Println(FindShortestPath(m, func(a, b State) bool {
return a.cnt+a.dist < b.cnt+b.dist
}))
}
func part2(inp []string, size, bytes int) {
m := h.NewCoordByteMap()
m.BRX, m.BRY = size, size
drops := parseInput(inp)
// We can skip up to 'bytes', part1 showed that that many work
for i := 0; i < bytes; i++ {
m.Put(drops[i], '#')
}
fmt.Println("# Part 2")
for tm, b := range drops[bytes+1:] {
m.Put(b, '#')
if FindShortestPath(m, func(a, b State) bool {
return a.dist < b.dist
}) == -1 {
fmt.Printf("Blocked at %d: %s\n", bytes+tm, b.String())
return
}
}
}
func parseInput(inp []string) []h.Coordinate {
var ret []h.Coordinate
for i := range inp {
c := h.Coordinate{}
fmt.Sscanf(inp[i], "%d,%d", &c.X, &c.Y)
ret = append(ret, c)
}
return ret
}
type State struct {
c h.Coordinate
cnt int
dist int
}
func FindShortestPath(inp h.CoordByteMap, less func(a, b State) bool) int {
visited := make(map[h.Coordinate]State)
end := h.Coordinate{X: inp.BRX, Y: inp.BRY}
start := h.Coordinate{X: 0, Y: 0}
startState := State{
c: start,
cnt: 0,
dist: start.Distance(end),
}
queue := h.NewHeap[State](less)
queue.Push(startState)
for queue.Len() > 0 {
step := queue.Pop()
if step.c.Equals(end) {
visited[end] = step
break
}
if _, ok := visited[step.c]; ok {
continue
}
visited[step.c] = step
// Find next steps
for _, n := range step.c.GetOrthNeighbors() {
if !inp.ContainsCoord(n) || inp.Get(n) == '#' {
continue
}
if _, ok := visited[n]; ok {
continue
}
nState := State{
c: n,
cnt: step.cnt + 1,
dist: n.Distance(end),
}
queue.Push(nState)
}
}
if v, ok := visited[end]; ok {
return v.cnt
}
return -1
}