day10.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package main
  2. import (
  3. "bufio"
  4. "flag"
  5. "fmt"
  6. "os"
  7. "time"
  8. )
  9. func main() {
  10. example := flag.Bool("example", false, "example or input")
  11. flag.Parse()
  12. filename := "input.txt"
  13. if *example {
  14. filename = "example.txt"
  15. }
  16. file, err := os.Open(filename)
  17. if err != nil {
  18. fmt.Println(err)
  19. return
  20. }
  21. defer file.Close()
  22. var grid [][]int
  23. scanner := bufio.NewScanner(file)
  24. for scanner.Scan() {
  25. line := scanner.Text()
  26. row := []int{}
  27. for _, c := range line {
  28. row = append(row, int(c-'0'))
  29. }
  30. grid = append(grid, row)
  31. }
  32. if err := scanner.Err(); err != nil {
  33. fmt.Println(err)
  34. return
  35. }
  36. // part 1
  37. start := time.Now()
  38. totalScore := calculateTrailheadScores(grid, bfs)
  39. end1 := time.Since(start)
  40. // part 2
  41. start = time.Now()
  42. totalRating := calculateTrailheadScores(grid, countUniqueTrails)
  43. end2 := time.Since(start)
  44. fmt.Println("Sum of Trailheads:", totalScore, "with time:", end1)
  45. fmt.Println("Sum of Rating:", totalRating, "with time:", end2)
  46. }
  47. func calculateTrailheadScores(grid [][]int, bfs func([][]int, int, int) int) int {
  48. totalScore := 0
  49. for y, row := range grid {
  50. for x, cell := range row {
  51. if cell == 0 {
  52. score := bfs(grid, x, y)
  53. totalScore += score
  54. }
  55. }
  56. }
  57. return totalScore
  58. }
  59. func countUniqueTrails(grid [][]int, startX, startY int) int {
  60. height, width := len(grid), len(grid[0])
  61. memo := make(map[[3]int]int)
  62. var dfs func(x, y, prevHeight int) int
  63. dfs = func(x, y, prevHeight int) int {
  64. if x < 0 || x >= width || y < 0 || y >= height || grid[y][x] != prevHeight+1 {
  65. return 0
  66. }
  67. if grid[y][x] == 9 {
  68. return 1
  69. }
  70. state := [3]int{x, y, grid[y][x]}
  71. if result, found := memo[state]; found {
  72. return result
  73. }
  74. directions := [][2]int{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}
  75. count := 0
  76. for _, d := range directions {
  77. nx, ny := x+d[0], y+d[1]
  78. count += dfs(nx, ny, grid[y][x])
  79. }
  80. memo[state] = count
  81. return count
  82. }
  83. return dfs(startX, startY, -1) // start with -1, to head 0
  84. }
  85. func bfs(grid [][]int, startX, startY int) int {
  86. directions := [][2]int{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}
  87. height, width := len(grid), len(grid[0])
  88. visited := make(map[[2]int]bool)
  89. queue := [][2]int{{startX, startY}}
  90. visited[[2]int{startX, startY}] = true
  91. reachableNines := 0
  92. for len(queue) > 0 {
  93. x, y := queue[0][0], queue[0][1]
  94. queue = queue[1:]
  95. for _, d := range directions {
  96. nx, ny := x+d[0], y+d[1]
  97. if nx < 0 || nx >= width || ny < 0 || ny >= height {
  98. continue
  99. }
  100. if !visited[[2]int{nx, ny}] && grid[ny][nx] == grid[y][x]+1 {
  101. visited[[2]int{nx, ny}] = true
  102. queue = append(queue, [2]int{nx, ny})
  103. if grid[ny][nx] == 9 {
  104. reachableNines++
  105. }
  106. }
  107. }
  108. }
  109. return reachableNines
  110. }