80 lines
1.6 KiB
Go
80 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"container/heap"
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
const bailFactor = 8
|
|
|
|
func main() {
|
|
inp := StdinToStringSlice()
|
|
fmt.Printf("# Part 1\nRisk level: %d\n", RiskLevel(inp))
|
|
fmt.Printf("# Part 2\nRescue minutes: %d\n", Rescue(inp))
|
|
}
|
|
|
|
func RiskLevel(input []string) int {
|
|
m := NewMap(input)
|
|
sum := 0
|
|
for y := 0; y <= m.target.y; y++ {
|
|
for x := 0; x <= m.target.x; x++ {
|
|
sum += m.Type(x, y)
|
|
}
|
|
}
|
|
return sum
|
|
}
|
|
|
|
func Rescue(input []string) int {
|
|
m := NewMap(input)
|
|
queue := PriorityQueue{
|
|
&Item{pos: coord{0, 0}, time: 0, equip: ToolTorch},
|
|
}
|
|
heap.Init(&queue)
|
|
|
|
type step struct {
|
|
coord coord
|
|
equip int
|
|
}
|
|
|
|
distances := map[step]int{
|
|
step{coord: coord{0, 0}, equip: ToolTorch}: 0,
|
|
}
|
|
|
|
for len(queue) > 0 {
|
|
item := (heap.Pop(&queue)).(*Item)
|
|
if item.pos.x == m.target.x && item.pos.y == m.target.y && item.equip == ToolTorch {
|
|
return item.time
|
|
}
|
|
|
|
// Check if we're wandering too far away
|
|
if item.pos.x > bailFactor*m.target.x || item.pos.y > bailFactor*m.target.y {
|
|
continue
|
|
}
|
|
|
|
if t, ok := distances[step{coord: item.pos, equip: item.equip}]; ok && t < item.time {
|
|
continue
|
|
}
|
|
|
|
for _, n := range m.Neighbors(item.pos, item.equip) {
|
|
d := step{coord: n.pos, equip: n.equip}
|
|
if t, ok := distances[step{coord: n.pos, equip: n.equip}]; !ok || item.time+n.time < t {
|
|
distances[d] = item.time + n.time
|
|
heap.Push(&queue, &Item{pos: n.pos, time: item.time + n.time, equip: n.equip})
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func StdinToStringSlice() []string {
|
|
var input []string
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
for scanner.Scan() {
|
|
input = append(input, scanner.Text())
|
|
}
|
|
return input
|
|
}
|