2018 Day 22 Complete
This commit is contained in:
111
2018/day22/map.go
Normal file
111
2018/day22/map.go
Normal file
@@ -0,0 +1,111 @@
|
||||
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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user