package main import ( "bufio" "fmt" "log" "os" "regexp" "strconv" "strings" ) var depth int var target *Pos func main() { input := stdinToStringSlice() reg, err := regexp.Compile("[^0-9]+") if err != nil { log.Fatal(err) } depth = Atoi(reg.ReplaceAllString(input[0], "")) tgt := strings.Trim(input[1], "target: ") tgtPts := strings.Split(tgt, ",") target = NewPos(Atoi(tgtPts[0]), Atoi(tgtPts[1]), depth) } func part1() { c := BuildCave(target) var risk int for y := 0; y <= target.y; y++ { for x := 0; x <= target.x; x++ { risk += c.risk(x, y, depth) } } fmt.Println("= Part 1 =") fmt.Println(risk) } func part2() { // Find shortest path form 0,0 to target // taking into account cost of changing gear // when necessary } type Cave struct { positions map[string]*Pos } func BuildCave(target *Pos) *Cave { c := &Cave{ positions: make(map[string]*Pos), } c.addPos(target) return c } func (c *Cave) addPos(p *Pos) { c.positions[p.string()] = p } func (c *Cave) getPos(x, y, z int) *Pos { var p *Pos var ok bool if p, ok = c.positions[c.buildKey(x, y, z)]; !ok { p = NewPos(x, y, z) c.addPos(p) } return p } func (c *Cave) buildKey(x, y, z int) string { return fmt.Sprintf( "(%d,%d,%d)", x, y, z, ) } func (c *Cave) getGeoIndex(x, y, z int) int { p := c.getPos(x, y, z) if p.geo < 0 { if x == 0 && y == 0 { p.geo = 0 } else if x == target.x && y == target.y { p.geo = 0 } else if y == 0 { p.geo = x * 16807 } else if x == 0 { p.geo = y * 48271 } else { p.geo = c.erosion(x-1, y, z) * c.erosion(x, y-1, z) } } return p.geo } func (c *Cave) erosion(x, y, z int) int { p := c.getPos(x, y, z) if p.erosion < 0 { p.erosion = (c.getGeoIndex(x, y, z) + z) % 20183 } return p.erosion } func (c *Cave) risk(x, y, z int) int { return c.erosion(x, y, z) % 3 } type Pos struct { x, y, z int geo, erosion int } func NewPos(x, y, z int) *Pos { r := &Pos{ x: x, y: y, z: z, geo: -1, erosion: -1, } return r } func (p *Pos) equals(n *Pos) bool { return p.x == n.x && p.y == n.y && p.z == n.z } func (p *Pos) string() string { return fmt.Sprintf( "(%d,%d,%d)", p.x, p.y, p.z, ) } func stdinToStringSlice() []string { var input []string scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { input = append(input, scanner.Text()) } return input } func Atoi(i string) int { var ret int var err error if ret, err = strconv.Atoi(i); err != nil { log.Fatal("Invalid Atoi: " + i) } return ret }