code.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. "strings"
  8. )
  9. const (
  10. Up = iota
  11. Down
  12. Left
  13. Right
  14. )
  15. type Point struct {
  16. y, x int
  17. direction int
  18. }
  19. func (p *Point) move(maze [][]byte, height int, width int) bool {
  20. switch maze[p.y][p.x] {
  21. case '|':
  22. if p.direction == Up && p.y-1 >= 0 {
  23. p.y--
  24. return true
  25. } else if p.direction == Down && p.y+1 < height {
  26. p.y++
  27. return true
  28. }
  29. case '-':
  30. if p.direction == Right && p.x+1 < width {
  31. p.x++
  32. return true
  33. } else if p.direction == Left && p.x-1 >= 0 {
  34. p.x--
  35. return true
  36. }
  37. case 'L':
  38. if p.direction == Down && p.x+1 < width {
  39. p.x++
  40. p.direction = Right
  41. return true
  42. } else if p.direction == Left && p.y-1 >= 0 {
  43. p.y--
  44. p.direction = Up
  45. return true
  46. }
  47. case 'J':
  48. if p.direction == Down && p.x-1 >= 0 {
  49. p.x--
  50. p.direction = Left
  51. return true
  52. } else if p.direction == Right && p.y-1 >= 0 {
  53. p.y--
  54. p.direction = Up
  55. return true
  56. }
  57. case '7':
  58. if p.direction == Right && p.y+1 < height {
  59. p.y++
  60. p.direction = Down
  61. return true
  62. } else if p.direction == Up && p.x-1 >= 0 {
  63. p.x--
  64. p.direction = Left
  65. return true
  66. }
  67. case 'F':
  68. if p.direction == Up && p.x+1 < width {
  69. p.x++
  70. p.direction = Right
  71. return true
  72. } else if p.direction == Left && p.y+1 < height {
  73. p.y++
  74. p.direction = Down
  75. return true
  76. }
  77. }
  78. return false
  79. }
  80. const (
  81. verticalAbove = "|7F"
  82. verticalBelow = "|LJ"
  83. horizontalLeft = "-LF"
  84. horizontalRight = "-J7"
  85. )
  86. func establishS(s Point, maze [][]byte, height int, width int) (byte, Point) {
  87. var left, right, up, down bool
  88. if s.x-1 >= 0 && strings.Contains(horizontalLeft, string(maze[s.y][s.x-1])) {
  89. left = true
  90. }
  91. if s.x+1 < width && strings.Contains(horizontalRight, string(maze[s.y][s.x+1])) {
  92. right = true
  93. }
  94. if s.y-1 >= 0 && strings.Contains(verticalAbove, string(maze[s.y-1][s.x])) {
  95. up = true
  96. }
  97. if s.y+1 < height && strings.Contains(verticalBelow, string(maze[s.y+1][s.x])) {
  98. down = true
  99. }
  100. var char byte
  101. if left {
  102. if right {
  103. char = '-'
  104. s.direction = Right
  105. } else if up {
  106. char = 'J'
  107. s.direction = Down
  108. } else if down {
  109. char = '7'
  110. s.direction = Up
  111. }
  112. } else if right {
  113. if up {
  114. char = 'L'
  115. s.direction = Down
  116. } else if down {
  117. char = 'F'
  118. s.direction = Up
  119. }
  120. } else if up {
  121. char = '|'
  122. s.direction = Down
  123. }
  124. return char, s
  125. }
  126. func part1(maze [][]byte) int {
  127. height := len(maze)
  128. width := len(maze[0])
  129. for y := range maze {
  130. for x := range maze[y] {
  131. if maze[y][x] == 'S' {
  132. char, start := establishS(Point{y: y, x: x}, maze, height, width)
  133. maze[y][x] = char
  134. current := start
  135. steps := 0
  136. for {
  137. if !current.move(maze, height, width) {
  138. break
  139. }
  140. steps++
  141. if current.x == start.x && current.y == start.y {
  142. return steps / 2
  143. }
  144. }
  145. }
  146. }
  147. }
  148. return -1
  149. }
  150. func readInput(file *os.File) [][]byte {
  151. scanner := bufio.NewScanner(file)
  152. var maze [][]byte
  153. width := -1
  154. for scanner.Scan() {
  155. line := scanner.Text()
  156. if line == "" {
  157. break
  158. }
  159. if width < 0 {
  160. width = len(line)
  161. }
  162. row := make([]byte, width)
  163. for i := range line {
  164. row[i] = line[i]
  165. }
  166. maze = append(maze, row)
  167. }
  168. return maze
  169. }
  170. func main() {
  171. if len(os.Args) < 2 {
  172. log.Fatal("You need to specify a file!")
  173. }
  174. filePath := os.Args[1]
  175. file, err := os.Open(filePath)
  176. if err != nil {
  177. log.Fatalf("Failed to open %s!\n", filePath)
  178. }
  179. maze := readInput(file)
  180. fmt.Println("Part1:", part1(maze))
  181. }