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 }