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)) } }