adventofcode/2018/day22/map.go

112 lines
2.3 KiB
Go
Raw Permalink Normal View History

2019-11-07 17:53:26 +00:00
package main
import "fmt"
const (
geologicY = 16807
geologicX = 48271
caveModulo = 20183
)
const (
TypeRocky = 0
TypeWet = 1
TypeNarrow = 2
)
const (
ToolNone = 1 << iota
ToolTorch
ToolGear
)
type Map struct {
target coord
depth int
geologicIndicesCache map[int]map[int]int
erosionLevelsCache map[int]map[int]int
}
func NewMap(input []string) *Map {
m := Map{}
m.geologicIndicesCache = make(map[int]map[int]int)
m.erosionLevelsCache = make(map[int]map[int]int)
if len(input) != 2 {
panic("Invalid Input")
}
_, err := fmt.Sscanf(input[0], "depth: %d", &m.depth)
if err != nil {
panic(err)
}
_, err = fmt.Sscanf(input[1], "target: %d,%d", &m.target.x, &m.target.y)
if err != nil {
panic(err)
}
return &m
}
func (m *Map) GeologicIndex(x, y int) int {
if m.geologicIndicesCache[y] != nil {
if i, ok := m.geologicIndicesCache[y][x]; ok {
return i
}
} else {
m.geologicIndicesCache[y] = make(map[int]int)
}
switch {
case x == 0 && y == 0, x == m.target.x && y == m.target.y:
m.geologicIndicesCache[y][x] = 0
case y == 0:
m.geologicIndicesCache[y][x] = x * geologicY
case x == 0:
m.geologicIndicesCache[y][x] = y * geologicX
default:
m.geologicIndicesCache[y][x] = m.ErosionLevel(x-1, y) * m.ErosionLevel(x, y-1)
}
return m.geologicIndicesCache[y][x]
}
func (m *Map) ErosionLevel(x, y int) int {
if m.erosionLevelsCache[y] != nil {
if level, ok := m.erosionLevelsCache[y][x]; ok {
return level
}
} else {
m.erosionLevelsCache[y] = make(map[int]int)
}
m.erosionLevelsCache[y][x] = (m.GeologicIndex(x, y) + m.depth) % caveModulo
return m.erosionLevelsCache[y][x]
}
func (m Map) Type(x, y int) int {
return m.ErosionLevel(x, y) % 3
}
func (m Map) Neighbors(pos coord, equip int) []Item {
var n []Item
for _, c := range pos.neighbors() {
t := m.Type(c.x, c.y)
if equip&allowed(t) != 0 {
n = append(n, Item{pos: c, equip: equip, time: 1})
n = append(n, Item{pos: c, equip: equip ^ allowed(t), time: 8})
}
}
return n
}
func allowed(regionType int) int {
switch regionType {
case TypeRocky:
return ToolGear | ToolTorch
case TypeWet:
return ToolGear | ToolNone
case TypeNarrow:
return ToolTorch | ToolNone
default:
panic(fmt.Errorf("unknown region type: %d", regionType))
}
}