114 lines
2.2 KiB
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
|
||
|
}
|