From 4016b42d19e8c34cc76e61f21e0e53d7bc014d6b Mon Sep 17 00:00:00 2001 From: Jeremy Kaplan Date: Tue, 14 Dec 2021 21:29:19 -0800 Subject: [PATCH] 2021 Day 15 Part 1 --- 2021/day15/main.go | 134 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 2021/day15/main.go diff --git a/2021/day15/main.go b/2021/day15/main.go new file mode 100644 index 0000000..b2340fa --- /dev/null +++ b/2021/day15/main.go @@ -0,0 +1,134 @@ +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 +}