package main import ( "fmt" helpers "git.bullercodeworks.com/brian/adventofcode/helpers" ) func main() { file := "input" if helpers.GetArgNumber(1) != "" { file = helpers.GetArgNumber(1) } v := NewVault(file) part1(v) } var keylist int var allNodes map[string]*Node func part1(v *Vault) { keylist = v.keylist allNodes = make(map[string]*Node) for k, v := range v.vault { if v { x, y, z := unc(k) n := Node{ X: x, Y: y, Z: z, steps: helpers.MAX_INT, } allNodes[c([]int{x, y})] = &n } } for _, v := range allNodes { n, ok := allNodes[c([]int{v.X, v.Y + 1})] if ok { v.N = n } e, ok := allNodes[c([]int{v.X + 1, v.Y})] if ok { v.E = e } s, ok := allNodes[c([]int{v.X, v.Y - 1})] if ok { v.S = s } w, ok := allNodes[c([]int{v.X - 1, v.Y})] if ok { v.W = w } } start := allNodes[c([]int{v.start.X, v.start.Y})] start.steps = 0 ProcessNode(start, 0, 0) } type Node struct { X, Y, Z int N, E, S, W *Node steps int visited bool } func ProcessNode(n *Node, steps, keys int) { if n.Z&keylist == keylist { fmt.Println("Steps to all Keys:", steps) return } for _, neighbor := range []*Node{n.N, n.E, n.S, n.W} { if neighbor == nil { continue } wrk, ok := allNodes[c([]int{neighbor.X, neighbor.Y})] if ok { if n.steps+1 < wrk.steps { wrk.steps = n.steps + 1 if !wrk.visited { ProcessNode(wrk, n.steps+1, keys) } } } } } type state struct { X, Y int keys int steps int } func FindPath(vault map[string]bool, doors, keys map[string]int, start helpers.Coordinate, keylist, currkeys int) int { queue := []state{state{X: start.X, Y: start.Y, keys: currkeys}} visited := make(map[string]bool) var st state for { st, queue = queue[0], queue[1:] fmt.Println(st.keys&keylist, keylist) if st.keys&keylist == keylist { return st.steps } visited[c([]int{st.X, st.Y, st.keys})] = true for _, v := range []*helpers.Coordinate{ start.GetNorthCoord(), start.GetEastCoord(), start.GetSouthCoord(), start.GetWestCoord(), } { wrk := helpers.NewCoordinate3d(v.X, v.Y, st.keys) if !vault[helpers.NewCoordinate(wrk.X, wrk.Y).String()] || visited[wrk.String()] { continue // Already been here, or can't be here } door, ok := doors[helpers.NewCoordinate(wrk.X, wrk.Y).String()] if ok && wrk.Z&door != door { fmt.Println("Hit door") continue // Space exists, but we can't open the door } key, ok := keys[helpers.NewCoordinate(wrk.X, wrk.Y).String()] if ok { fmt.Println("Getting Key") wrk.Z |= key // Pick up the key } queue = append(queue, state{X: wrk.X, Y: wrk.Y, keys: wrk.Z, steps: st.steps + 1}) } } } func isDoor(b byte) bool { return 'A' <= b && b <= 'Z' } func isKey(b byte) bool { return 'a' <= b && b <= 'z' } func keyToDoor(b byte) byte { return (b - 'a') + 'A' } func doorToKey(b byte) byte { return (b - 'A') + 'a' } func keyInt(b byte) int { return 1 << (b - 'a') } func doorInt(b byte) int { return 1 << (b - 'A') } func c(vals []int) string { if len(vals) == 2 { return fmt.Sprintf("[%d, %d]", vals[0], vals[1]) } else if len(vals) == 3 { return fmt.Sprintf("[%d, %d, %d]", vals[0], vals[1], vals[2]) } return "" } func unc(c string) (int, int, int) { var x, y, z int _, err := fmt.Sscanf(c, "[%d, %d, %d]", &x, &y, &z) if err == nil { return x, y, z } _, err = fmt.Sscanf(c, "[%d, %d]", &x, &y) if err != nil { panic(err) } return x, y, 0 }