package main import ( "bufio" "fmt" "os" "strings" "time" intcode "git.bullercodeworks.com/brian/adventofcode/2019/intcode-processor" helpers "git.bullercodeworks.com/brian/adventofcode/helpers" ) var auto bool var maze *Maze func main() { progFileName := "input" auto = true if len(os.Args) > 1 && os.Args[1] == "-manual" { auto = false } prog := intcode.ReadIntCodeFile(progFileName) maze = NewMaze() part1(prog) part2() } var all map[string]*MazeCoord func part1(prog []int) { p := intcode.NewProgram(prog) go func() { var roadTaken []helpers.Coordinate for { //time.Sleep(500) //fmt.Println(helpers.CLEAR_SCREEN) //maze.Print() for !p.NeedsInput() { time.Sleep(1) } var movingDir int var moveToCoord *helpers.Coordinate if auto { var picked bool directions := []int{DIR_N, DIR_E, DIR_S, DIR_W} // If we have an unexplored location, try it for _, tryDir := range directions { v := maze.GetCoord(maze.GetDirFromBot(tryDir)) if v == MAZE_UNKNOWN { movingDir = tryDir picked = true break } } if !picked { movingDir = maze.GetDirectionToLast() if movingDir == -1 { fmt.Println("Maze Created") p.ForceQuit() return } picked = true } moveToCoord = maze.GetDirFromBot(movingDir) } else { for movingDir == 0 { fmt.Print("Input (vimlike): ") reader := bufio.NewReader(os.Stdin) inp, err := reader.ReadString('\n') if err != nil { panic(err) } inp = strings.TrimSpace(inp) switch inp { case "h": // West movingDir = DIR_W moveToCoord = maze.bot.GetWestCoord() case "j": // South movingDir = DIR_S moveToCoord = maze.bot.GetSouthCoord() case "k": // North movingDir = DIR_N moveToCoord = maze.bot.GetNorthCoord() case "l": // East movingDir = DIR_E moveToCoord = maze.bot.GetEastCoord() } } } p.Input(movingDir) for !p.NeedsOutput() { time.Sleep(1) } moveRes := p.Output() maze.SetCoord(moveToCoord, moveRes) switch moveRes { case 1, 2: // Moved roadTaken = append(roadTaken, *maze.bot) maze.MoveBot(movingDir) } if p.State() == intcode.RET_DONE || p.State() == intcode.RET_ERR { break } } }() p.Run() //We force quit the program when the maze is built. // Now we find the quickest path through the maze. fmt.Println(helpers.CLEAR_SCREEN) maze.Print() fmt.Println("Now find shortest path") all = make(map[string]*MazeCoord) for k, v := range maze.maze { if v == MAZE_EMPTY || v == MAZE_O2SYS { c := helpers.CoordinateFromString(k) m := &MazeCoord{coord: c} m.Distance = helpers.MAX_INT all[c.String()] = m } } for _, v := range all { n, ok := all[v.coord.GetNorthCoord().String()] if ok { v.N = n } e, ok := all[v.coord.GetEastCoord().String()] if ok { v.E = e } s, ok := all[v.coord.GetSouthCoord().String()] if ok { v.S = s } w, ok := all[v.coord.GetWestCoord().String()] if ok { v.W = w } } start := all[maze.startCoord.String()] start.Distance = 0 fmt.Println("Processing. . .") ProcessNode(start, 0) fmt.Println("Distance to O2:", all[maze.o2Coord.String()].Distance) } func ProcessNode(m *MazeCoord, steps int) { if m.coord.String() == maze.o2Coord.String() { return } for _, neighbor := range []*MazeCoord{m.N, m.E, m.S, m.W} { if neighbor == nil { continue } wrk, ok := all[neighbor.coord.String()] if ok { if m.Distance+1 < wrk.Distance { wrk.Distance = m.Distance + 1 if !wrk.Visited { ProcessNode(wrk, m.Distance+1) } } } } m.Visited = true } func part2() { // We're going to reuse the visited flag for oxygen for _, v := range all { v.Visited = false } fmt.Println("Unfilled", countUnfilledSpaces()) all[maze.o2Coord.String()].Visited = true var cnt int for countUnfilledSpaces() > 0 { tick() fmt.Println("Unfilled", countUnfilledSpaces()) cnt++ } fmt.Println("Minutes:", cnt) } func countUnfilledSpaces() int { var count int for _, v := range all { if !v.Visited { count++ } } return count } func tick() bool { // Start with the o2 coord var toFill []*MazeCoord for _, v := range all { if v.N != nil && v.N.Visited { toFill = append(toFill, v) continue } if v.E != nil && v.E.Visited { toFill = append(toFill, v) continue } if v.S != nil && v.S.Visited { toFill = append(toFill, v) continue } if v.W != nil && v.W.Visited { toFill = append(toFill, v) continue } } for k := range toFill { all[toFill[k].coord.String()].Visited = true } fmt.Println("Filled", len(toFill), "spaces") return len(toFill) > 0 } type MazeCoord struct { coord *helpers.Coordinate N, S, E, W *MazeCoord Distance int Visited bool }