diff --git a/2019/day15/main.go b/2019/day15/main.go index 0e1a002..61be563 100644 --- a/2019/day15/main.go +++ b/2019/day15/main.go @@ -8,10 +8,13 @@ import ( "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" @@ -19,20 +22,49 @@ func main() { auto = true } prog := intcode.ReadIntCodeFile(progFileName) + maze = NewMaze() + play(prog) } func play(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 { - var gotInput bool - for !gotInput { + for movingDir == 0 { fmt.Print("Input (vimlike): ") reader := bufio.NewReader(os.Stdin) inp, err := reader.ReadString('\n') @@ -41,38 +73,40 @@ func play(prog []int) { } inp = strings.TrimSpace(inp) switch inp { - case "h": - p.Input(3) - gotInput = true - case "j": - p.Input(2) - gotInput = true - case "k": - p.Input(1) - gotInput = true - case "l": - p.Input(4) - gotInput = true + 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 0: // Hit a wall - fmt.Println("WALL") - case 1: // Moved - fmt.Println("OK") - case 2: // Moved and done - fmt.Println("DONE") + case 1, 2: // Moved + roadTaken = append(roadTaken, *maze.bot) + maze.MoveBot(movingDir) + } + if p.State() == intcode.RET_DONE || p.State() == intcode.RET_ERR { + break } } }() ret := p.Run() if ret == intcode.RET_DONE { - + maze.Print() } else if ret == intcode.RET_ERR { fmt.Println("ERROR") fmt.Println(p.Error()) diff --git a/2019/day15/maze.go b/2019/day15/maze.go new file mode 100644 index 0000000..94a117b --- /dev/null +++ b/2019/day15/maze.go @@ -0,0 +1,139 @@ +package main + +import ( + "fmt" + + helpers "git.bullercodeworks.com/brian/adventofcode/helpers" +) + +const ( + MAZE_UNKNOWN = -1 + MAZE_WALL = 0 + MAZE_EMPTY = 1 + MAZE_O2SYS = 2 +) + +const ( + DIR_N = 1 + DIR_S = 2 + DIR_W = 3 + DIR_E = 4 +) + +type Maze struct { + maze map[string]int + maxX, minX int + maxY, minY int + bot *helpers.Coordinate + path []*helpers.Coordinate + dirHistory []int + dnt bool +} + +func NewMaze() *Maze { + m := &Maze{ + maze: make(map[string]int), + maxX: helpers.MIN_INT, + minX: helpers.MAX_INT, + maxY: helpers.MIN_INT, + minY: helpers.MAX_INT, + bot: helpers.NewCoordinate(0, 0), + } + m.path = append(m.path, helpers.NewCoordinate(0, 0)) + return m +} + +func (m *Maze) SetCoord(c *helpers.Coordinate, val int) { + m.maze[c.String()] = val + if m.maxX < c.X { + m.maxX = c.X + } + if m.minX > c.X { + m.minX = c.X + } + if m.maxY < c.Y { + m.maxY = c.Y + } + if m.minY > c.Y { + m.minY = c.Y + } +} + +func (m *Maze) GetCoord(c *helpers.Coordinate) int { + v, ok := m.maze[c.String()] + if !ok { + return MAZE_UNKNOWN + } + return v +} + +func (m *Maze) GetDirFromBot(dir int) *helpers.Coordinate { + switch dir { + case DIR_N: + return m.bot.GetNorthCoord() + case DIR_E: + return m.bot.GetEastCoord() + case DIR_S: + return m.bot.GetSouthCoord() + case DIR_W: + return m.bot.GetWestCoord() + } + return nil +} + +func (m *Maze) MoveBot(dir int) bool { + dest := m.GetDirFromBot(dir) + if m.GetCoord(dest) == MAZE_UNKNOWN || m.GetCoord(dest) == MAZE_WALL { + return false + } + m.bot.X, m.bot.Y = dest.X, dest.Y + if !m.dnt { + m.path = append(m.path, helpers.NewCoordinate(m.bot.X, m.bot.Y)) + m.dirHistory = append(m.dirHistory, dir) + } + m.dnt = false + return true +} + +func (m *Maze) GetDirectionToLast() int { + if len(m.dirHistory) == 0 { + return -1 + } + m.dnt = true + var dir int + dir, m.dirHistory = m.dirHistory[len(m.dirHistory)-1], m.dirHistory[:len(m.dirHistory)-1] + switch dir { + case DIR_N: + return DIR_S + case DIR_S: + return DIR_N + case DIR_W: + return DIR_E + case DIR_E: + return DIR_W + } + return -1 +} + +func (m *Maze) Print() { + for y := m.minY; y <= m.maxY; y++ { + for x := m.minX; x <= m.maxX; x++ { + c := helpers.NewCoordinate(x, y) + if m.bot.Equals(*c) { + fmt.Print("%") + } else { + switch m.GetCoord(c) { + case MAZE_UNKNOWN: + fmt.Print("~") + case MAZE_WALL: + fmt.Print("#") + case MAZE_EMPTY: + fmt.Print(" ") + case MAZE_O2SYS: + fmt.Print("O") + } + } + } + fmt.Println() + } +} diff --git a/2019/intcode-processor/processor.go b/2019/intcode-processor/processor.go index 39638c0..21ef73b 100644 --- a/2019/intcode-processor/processor.go +++ b/2019/intcode-processor/processor.go @@ -44,6 +44,7 @@ type Program struct { state int error error + bail bool waitingForInput bool input chan int waitingForOutput bool @@ -113,6 +114,12 @@ func (p *Program) Error() error { return p.error } +func (p *Program) ForceQuit() { + p.bail = true + close(p.input) + close(p.output) +} + func (p *Program) Run() int { for { p.state = p.Step() @@ -123,6 +130,10 @@ func (p *Program) Run() int { } func (p *Program) Step() int { + if p.bail { + p.error = errors.New("Force Quit") + return RET_ERR + } if len(p.code) < p.ptr { p.error = errors.New("Pointer Exception") return RET_ERR diff --git a/helpers/coordinate.go b/helpers/coordinate.go index d89d49c..46edcbe 100644 --- a/helpers/coordinate.go +++ b/helpers/coordinate.go @@ -10,6 +10,35 @@ type Coordinate struct { X, Y int } +func NewCoordinate(x, y int) *Coordinate { + return &Coordinate{x, y} +} + +func (c *Coordinate) GetNorthCoord() *Coordinate { + return &Coordinate{ + X: c.X, + Y: c.Y - 1, + } +} +func (c *Coordinate) GetEastCoord() *Coordinate { + return &Coordinate{ + X: c.X + 1, + Y: c.Y, + } +} +func (c *Coordinate) GetSouthCoord() *Coordinate { + return &Coordinate{ + X: c.X, + Y: c.Y + 1, + } +} +func (c *Coordinate) GetWestCoord() *Coordinate { + return &Coordinate{ + X: c.X - 1, + Y: c.Y, + } +} + func CoordinateFromString(str string) *Coordinate { c := Coordinate{} r := strings.NewReader(str) @@ -35,3 +64,7 @@ func (c Coordinate) String() string { func (c Coordinate) Distance(t Coordinate) int { return AbsInt(c.X-t.X) + AbsInt(c.Y-t.Y) } + +func (c Coordinate) Equals(c2 Coordinate) bool { + return c.X == c2.X && c.Y == c2.Y +}