package main import ( "bufio" "fmt" "os" ) const FILE_PATH = "./input.txt" //const FILE_PATH = "./sample.txt" func LoadInput(filename string) ([]string, error) { file, err := os.Open(filename) if err != nil { return nil, err } defer file.Close() var lines []string scanner := bufio.NewScanner(file) for scanner.Scan() { lines = append(lines, scanner.Text()) } if err := scanner.Err(); err != nil { return nil, err } return lines, nil } type Vector2 struct { x int y int } type structuredInput = [][]byte func TransformInput(lines []string) structuredInput { var result = make([][]byte, 0) for _, line := range lines { result = append(result, []byte(line)) } return result } const ( UP = iota RIGHT = iota DOWN = iota LEFT = iota ) var MOVEMENTS = []Vector2{ {0, -1}, {1, 0}, {0, 1}, {-1, 0}, } func addVectors(a Vector2, b Vector2) Vector2 { return Vector2{a.x + b.x, a.y + b.y} } func inBounds(point Vector2, limit Vector2) bool { return point.x >= 0 && point.x < limit.x && point.y >= 0 && point.y < limit.y } func Part1(input structuredInput) int { var result = 0 var guard Vector2 = Vector2{} var direction int = UP var bounds Vector2 = Vector2{len(input[0]), len(input)} var visited [][]bool = make([][]bool, len(input)) var next Vector2 for i := range visited { visited[i] = make([]bool, len(input[i])) } for y := 0; y < len(input); y++ { for x := 0; x < len(input[y]); x++ { if input[y][x] == '^' { guard.x = x guard.y = y } } } visited[guard.y][guard.x] = true for inBounds(addVectors(guard, MOVEMENTS[direction]), bounds) { next = addVectors(guard, MOVEMENTS[direction]) if input[next.y][next.x] == '#' { direction = (direction + 1) % 4 continue } guard = next visited[guard.y][guard.x] = true } for i := range visited { for j := range visited[i] { if visited[i][j] { result++ } } } return result } var visited [][][]bool func generateVisited(bounds Vector2) { visited = make([][][]bool, 4) for i := range visited { visited[i] = make([][]bool, bounds.y) for j := range visited[i] { visited[i][j] = make([]bool, bounds.x) } } } func resetVisited() { for i := range visited { for j := range visited[i] { for m := range visited[i][j] { visited[i][j][m] = false } } } } func setPositionAsVisited(position Vector2, direction int) { visited[direction][position.y][position.x] = true } func hasVisited(position Vector2, direction int) bool { return visited[direction][position.y][position.x] } func checkForLoop(field [][]byte, startPosition Vector2, bounds Vector2) bool { var guard Vector2 = Vector2{startPosition.x, startPosition.y} var direction = UP var next Vector2 resetVisited() setPositionAsVisited(guard, direction) for inBounds(addVectors(guard, MOVEMENTS[direction]), bounds) { next = addVectors(guard, MOVEMENTS[direction]) if field[next.y][next.x] == '#' { direction = (direction + 1) % 4 continue } guard = next if hasVisited(guard, direction) { return true } setPositionAsVisited(guard, direction) } return false } func Part2(input structuredInput) int { var result = 0 var guard Vector2 = Vector2{} var bounds Vector2 = Vector2{len(input[0]), len(input)} generateVisited(bounds) for y := 0; y < len(input); y++ { for x := 0; x < len(input[y]); x++ { if input[y][x] == '^' { guard.x = x guard.y = y } } } for y := 0; y < len(input); y++ { for x := 0; x < len(input[y]); x++ { if input[y][x] == '.' { input[y][x] = '#' if checkForLoop(input, guard, bounds) { result++ } input[y][x] = '.' } } } return result } func main() { input, err := LoadInput(FILE_PATH) if err != nil { fmt.Println("Error loading input:", err) return } structuredInput := TransformInput(input) fmt.Println("Structured Input:", structuredInput) fmt.Println("Solution Part 1: ", Part1(structuredInput)) fmt.Println("Solution Part 2: ", Part2(structuredInput)) }