2021 Day 15 Part 1
This commit is contained in:
parent
6ccd3ed4b0
commit
4016b42d19
1 changed files with 134 additions and 0 deletions
134
2021/day15/main.go
Normal file
134
2021/day15/main.go
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue