package main import ( "fmt" "time" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) func main() { inp := h.StdinToCoordMap() cp := inp.Copy() m := part1(inp) part2(*cp, m.FindAll('X')) } var debug = false func part1(m h.CoordByteMap) h.CoordByteMap { init, err := m.FindFirst('^') h.CheckErr(err) for moveGuard(m) { if debug { fmt.Println(h.CLEAR_SCREEN) fmt.Println(m) guard := m.FindAll('^', '>', 'v', '<')[0] fmt.Println(guard) time.Sleep(time.Second / 10) } } fmt.Println() fmt.Println("# Part 1") fmt.Printf("Guard moved into %d positions.\n", m.Count('X')) fmt.Println() m.Put(init, '^') return m } func part2(clean h.CoordByteMap, p []h.Coordinate) { // m should have all of the 'X' spots where the guard moved in part 1 init, err := clean.FindFirst('^') h.CheckErr(err) var obstacles []h.Coordinate for i := range p { fmt.Println(h.CLEAR_SCREEN) fmt.Print("Progress: ") h.PrintProgress(i, len(p)) fmt.Printf(" %d/%d\n", i, len(p)) m := *clean.Copy() // Try putting an obstacle at p[i] m.Put(p[i], 'O') history := make(map[h.Coordinate][]string) guard := m.FindAll('^', '>', 'v', '<')[0] tst := m.Get(guard) history[guard] = append(history[guard], string(tst)) var foundLoop bool for moveGuard(m) && !foundLoop { // fmt.Print(".") if debug { fmt.Println(h.CLEAR_SCREEN) fmt.Println(m) guard := m.FindAll('^', '>', 'v', '<')[0] fmt.Printf("Guard: %s - Testing Obstacle: %s\n", guard, p[i]) fmt.Println(obstacles) fmt.Println(history) time.Sleep(time.Second / 10) } guard := m.FindAll('^', '>', 'v', '<')[0] bt := m.Get(guard) // Check if we already have this position/orientation in our history for j := range history[guard] { if history[guard][j] == string(bt) { if !contains(obstacles, p[i]) { obstacles = append(obstacles, p[i]) foundLoop = true if debug { fmt.Println("Found Loop:", string(history[guard][j]), "==", string(bt)) } break } } } history[guard] = append(history[guard], string(bt)) } m.Put(p[i], '.') m.Put(init, '^') } fmt.Println() fmt.Println("# Part 2") fmt.Printf("Obstacle positions to create a loop: %d\n", len(obstacles)) // 583 is too low } func checkForLoop(m h.CoordByteMap) { } func contains(sl []h.Coordinate, c h.Coordinate) bool { for i := range sl { if sl[i].Equals(c) { return true } } return false } func turn(g byte) byte { switch g { case '^': return '>' case '>': return 'v' case 'v': return '<' default: return '^' } } func nextPos(guard h.Coordinate, m h.CoordByteMap) h.Coordinate { switch m.Get(guard) { case '>': return guard.East() case 'v': return guard.South() case '<': return guard.West() } return guard.North() } func moveGuard(m h.CoordByteMap) bool { guard := m.FindAll('^', '>', 'v', '<')[0] currBt := m.Get(guard) turn := turn(currBt) next := nextPos(guard, m) if !m.ContainsCoord(next) { m.Put(guard, 'X') return false } tst := m.Get(next) if tst == '#' || tst == 'O' { m.Put(guard, turn) return moveGuard(m) } m.Put(guard, 'X') m.Put(next, currBt) return true }