package main import ( "bufio" "fmt" "os" "strconv" "time" ) 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 structuredInput = [][]int func TransformInput(lines []string) structuredInput { var result = make([][]int, len(lines)) for i := 0; i < len(lines); i++ { result[i] = make([]int, len(lines[i])) for j := 0; j < len(lines[i]); j++ { result[i][j] = int(lines[i][j] - '0') } } return result } func isInBounds(position Vector2, bounds Vector2) bool { return position.x >= 0 && position.x < bounds.x && position.y >= 0 && position.y < bounds.y } func print2DIntArray(input [][]int, padding int, sep string) { var numb string for y := 0; y < len(input); y++ { for x := 0; x < len(input[y]); x++ { numb = strconv.Itoa(input[y][x]) for len(numb) < padding { numb = "0" + numb } fmt.Print(numb, sep) } fmt.Println() } fmt.Println() } type Vector2 struct { x int y int } func add(a Vector2, b Vector2) Vector2 { return Vector2{a.x + b.x, a.y + b.y} } var MOVEMENTS = []Vector2{ {0, -1}, {1, 0}, {0, 1}, {-1, 0}, } func calcPossibleEndPoints(input structuredInput, startPost Vector2) int { var possiblePoints map[Vector2]bool = make(map[Vector2]bool) var nextPoints map[Vector2]bool var bounds = Vector2{len(input[0]), len(input)} var nextPoint Vector2 possiblePoints[startPost] = true for i := 1; i <= 9; i++ { nextPoints = make(map[Vector2]bool) for point := range possiblePoints { for j := 0; j < len(MOVEMENTS); j++ { nextPoint = add(point, MOVEMENTS[j]) if isInBounds(nextPoint, bounds) && input[nextPoint.y][nextPoint.x] == i { nextPoints[nextPoint] = true } } } possiblePoints = nextPoints } return len(possiblePoints) } func calcTrailRating(input structuredInput, startPost Vector2) int { var possiblePoints []Vector2 = make([]Vector2, 0) var nextPoints []Vector2 var bounds = Vector2{len(input[0]), len(input)} var nextPoint Vector2 possiblePoints = append(possiblePoints, startPost) for i := 1; i <= 9; i++ { nextPoints = make([]Vector2, 0) for _, point := range possiblePoints { for j := 0; j < len(MOVEMENTS); j++ { nextPoint = add(point, MOVEMENTS[j]) if isInBounds(nextPoint, bounds) && input[nextPoint.y][nextPoint.x] == i { nextPoints = append(nextPoints, nextPoint) } } } possiblePoints = nextPoints } return len(possiblePoints) } func Part1(input structuredInput) int { var result = 0 for y := 0; y < len(input); y++ { for x := 0; x < len(input[y]); x++ { if input[y][x] == 0 { result += calcPossibleEndPoints(input, Vector2{x, y}) } } } return result } func Part2(input structuredInput) int { var result = 0 for y := 0; y < len(input); y++ { for x := 0; x < len(input[y]); x++ { if input[y][x] == 0 { result += calcTrailRating(input, Vector2{x, y}) } } } return result } func main() { var start time.Time var elapsed time.Duration = 0 input, err := LoadInput(FILE_PATH) if err != nil { fmt.Println("Error loading input:", err) return } structuredInput := TransformInput(input) fmt.Println("Structured Input:", structuredInput) start = time.Now() fmt.Println("Solution Part 1: ", Part1(structuredInput)) elapsed = time.Since(start) fmt.Printf("Part 1 took %s\n", elapsed) start = time.Now() fmt.Println("Solution Part 2: ", Part2(structuredInput)) elapsed = time.Since(start) fmt.Printf("Part 2 took %s\n", elapsed) }