code.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. )
  8. const (
  9. None = iota
  10. North
  11. South
  12. East
  13. West
  14. )
  15. type Point struct {
  16. y, x int
  17. steps int
  18. direction int
  19. mustGoDown bool
  20. }
  21. func readInput(file *os.File) [][]byte {
  22. scanner := bufio.NewScanner(file)
  23. var board [][]byte
  24. for scanner.Scan() {
  25. line := scanner.Text()
  26. if line == "" {
  27. break
  28. }
  29. var row []byte
  30. for i := range line {
  31. row = append(row, line[i])
  32. }
  33. board = append(board, row)
  34. }
  35. return board
  36. }
  37. const (
  38. Up = '^'
  39. Right = '>'
  40. Down = 'V'
  41. Left = '<'
  42. Rock = '#'
  43. )
  44. func (p *Point) getDestinations(board [][]byte, height int, width int) []Point {
  45. var destinations []Point
  46. p.steps++
  47. if p.mustGoDown && p.y+1 < height && board[p.y+1][p.x] != Rock {
  48. p.y++
  49. p.direction = None
  50. p.mustGoDown = false
  51. destinations = append(destinations, *p)
  52. return destinations
  53. }
  54. switch board[p.y][p.x] {
  55. case Up:
  56. p.direction = North
  57. p.mustGoDown = true
  58. case Down:
  59. p.direction = South
  60. p.mustGoDown = true
  61. case Left:
  62. p.direction = West
  63. p.mustGoDown = true
  64. case Right:
  65. p.direction = East
  66. p.mustGoDown = true
  67. }
  68. if p.direction != None {
  69. switch p.direction {
  70. case North:
  71. p.y--
  72. case South:
  73. p.y++
  74. case West:
  75. p.x--
  76. case East:
  77. p.x++
  78. }
  79. destinations = append(destinations, *p)
  80. return destinations
  81. }
  82. if p.y-1 >= 0 && board[p.y-1][p.x] != Rock {
  83. destinations = append(destinations, Point{y: p.y - 1, x: p.x, steps: p.steps})
  84. }
  85. if p.x+1 < width && board[p.y][p.x+1] != Rock {
  86. destinations = append(destinations, Point{y: p.y, x: p.x + 1, steps: p.steps})
  87. }
  88. if p.x-1 >= 0 && board[p.y][p.x-1] != Rock {
  89. destinations = append(destinations, Point{y: p.y, x: p.x - 1, steps: p.steps})
  90. }
  91. if p.y+1 < height && board[p.y+1][p.x] != Rock {
  92. destinations = append(destinations, Point{y: p.y + 1, x: p.x, steps: p.steps})
  93. }
  94. return destinations
  95. }
  96. func (p *Point) key() string {
  97. return fmt.Sprintf("%d_%d", p.y, p.x)
  98. }
  99. func calculate(board [][]byte) int {
  100. height := len(board)
  101. width := len(board[0])
  102. start := Point{y: 0, x: 1}
  103. goal := Point{y: height - 1, x: width - 2}
  104. visited := make(map[string]int)
  105. visited[start.key()] = start.steps
  106. frontier := []Point{start}
  107. var max int
  108. for {
  109. if len(frontier) == 0 {
  110. break
  111. }
  112. last := len(frontier) - 1
  113. current := frontier[last]
  114. frontier = frontier[:last]
  115. if current.x == goal.x && current.y == goal.y {
  116. if max < current.steps {
  117. max = current.steps
  118. }
  119. continue
  120. }
  121. successors := current.getDestinations(board, height, width)
  122. for i := range successors {
  123. _, ok := visited[successors[i].key()]
  124. if !ok {
  125. visited[successors[i].key()] = successors[i].steps
  126. frontier = append(frontier, successors[i])
  127. }
  128. }
  129. }
  130. return max
  131. }
  132. func main() {
  133. if len(os.Args) < 2 {
  134. log.Fatal("You need to specify a file!")
  135. }
  136. filePath := os.Args[1]
  137. file, err := os.Open(filePath)
  138. if err != nil {
  139. log.Fatalf("Failed to open %s!\n", filePath)
  140. }
  141. board := readInput(file)
  142. fmt.Println("Part1:", calculate(board))
  143. }