Watch
1
0
Fork
You've already forked advent-of-code
0
advent-of-code/2021/day15/main.go
2021-12-14 21:29:19 -08:00

134 lines
2.1 KiB
Go

package main
import (
"container/heap"
"fmt"
"github.com/jdkaplan/advent-of-code/aoc"
)
func main() {
lines := aoc.Input().ReadLines("day15.txt")
fmt.Println(part1(lines))
}
func part1(lines []string) int {
g := NewGrid(lines)
return lowrisk(g, RC{0, 0}, RC{g.Rows - 1, g.Cols - 1})
}
type RC struct{ r, c int }
type Grid struct {
Rows int
Cols int
m map[RC]int
}
func NewGrid(lines []string) Grid {
g := Grid{
m: make(map[RC]int),
Rows: len(lines),
Cols: len(lines[0]),
}
for r, row := range lines {
for c, col := range row {
g.m[RC{r, c}] = int(col - '0')
}
}
return g
}
func (g Grid) Neighbors(rc RC) (ns []RC) {
r, c := rc.r, rc.c
for _, n := range []RC{
{r - 1, c},
{r, c - 1},
{r, c + 1},
{r + 1, c},
} {
if 0 <= n.r && n.r < g.Rows && 0 <= n.c && n.c < g.Cols {
ns = append(ns, n)
}
}
return
}
func (g Grid) Risk(rc RC) int {
return g.m[rc]
}
func lowrisk(g Grid, start, goal RC) (risk int) {
pq := make(PriorityQueue, 1)
pq[0] = &Node{
rc: start,
cost: 0,
idx: 0,
}
heap.Init(&pq)
seen := make(map[RC]bool)
for len(pq) > 0 {
rc, cost := pq.Next()
if rc == goal {
return cost
}
if seen[rc] {
continue
}
for _, n := range g.Neighbors(rc) {
pq.Insert(n, cost+g.Risk(n))
}
seen[rc] = true
}
return -1
}
type Node struct {
rc RC
cost int
idx int
}
type PriorityQueue []*Node
func (pq *PriorityQueue) Next() (rc RC, cost int) {
n := heap.Pop(pq).(*Node)
return n.rc, n.cost
}
func (pq *PriorityQueue) Insert(rc RC, cost int) {
heap.Push(pq, &Node{rc: rc, cost: cost})
}
func (pq PriorityQueue) Len() int {
return len(pq)
}
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].cost < pq[j].cost
}
func (p PriorityQueue) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
p[i].idx = i
p[j].idx = j
}
func (pq *PriorityQueue) Push(x interface{}) {
n := len(*pq)
node := x.(*Node)
node.idx = n
*pq = append(*pq, node)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
node := old[n-1]
old[n-1] = nil
node.idx = -1
*pq = old[0 : n-1]
return node
}