code.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. )
  8. type move struct {
  9. direction byte
  10. steps int
  11. }
  12. func readInput(file *os.File) []move {
  13. scanner := bufio.NewScanner(file)
  14. var moves []move
  15. for scanner.Scan() {
  16. line := scanner.Text()
  17. if line == "" {
  18. continue
  19. }
  20. var current move
  21. n, err := fmt.Sscanf(line, "%c %d", &current.direction, &current.steps)
  22. if n != 2 || err != nil {
  23. log.Fatal("Can't parse cd:", err)
  24. }
  25. moves = append(moves, current)
  26. }
  27. return moves
  28. }
  29. type point struct {
  30. x int
  31. y int
  32. }
  33. type headTail struct {
  34. head point
  35. tail point
  36. }
  37. func tailInVicinity(tracker headTail) bool {
  38. return tracker.tail.x >= tracker.head.x-1 && tracker.tail.x <= tracker.head.x+1 && tracker.tail.y >= tracker.head.y-1 && tracker.tail.y <= tracker.head.y+1
  39. }
  40. func moveRight(tracker headTail, trail map[point]bool, steps int) (headTail, map[point]bool) {
  41. limit := tracker.head.x + steps
  42. for i := tracker.head.x + 1; i <= limit; i++ {
  43. tracker.head.x = i
  44. if !tailInVicinity(tracker) {
  45. tracker.tail.y = tracker.head.y
  46. tracker.tail.x = i - 1
  47. trail[tracker.tail] = true
  48. }
  49. }
  50. return tracker, trail
  51. }
  52. func moveLeft(tracker headTail, trail map[point]bool, steps int) (headTail, map[point]bool) {
  53. limit := tracker.head.x - steps
  54. for i := tracker.head.x - 1; i >= limit; i-- {
  55. tracker.head.x = i
  56. if !tailInVicinity(tracker) {
  57. tracker.tail.y = tracker.head.y
  58. tracker.tail.x = i + 1
  59. trail[tracker.tail] = true
  60. }
  61. }
  62. return tracker, trail
  63. }
  64. func moveUp(tracker headTail, trail map[point]bool, steps int) (headTail, map[point]bool) {
  65. limit := tracker.head.y + steps
  66. for i := tracker.head.y + 1; i <= limit; i++ {
  67. tracker.head.y = i
  68. if !tailInVicinity(tracker) {
  69. tracker.tail.x = tracker.head.x
  70. tracker.tail.y = i - 1
  71. trail[tracker.tail] = true
  72. }
  73. }
  74. return tracker, trail
  75. }
  76. func moveDown(tracker headTail, trail map[point]bool, steps int) (headTail, map[point]bool) {
  77. limit := tracker.head.y - steps
  78. for i := tracker.head.y - 1; i >= limit; i-- {
  79. tracker.head.y = i
  80. if !tailInVicinity(tracker) {
  81. tracker.tail.x = tracker.head.x
  82. tracker.tail.y = i + 1
  83. trail[tracker.tail] = true
  84. }
  85. }
  86. return tracker, trail
  87. }
  88. func drawTail(tracker headTail, action move, trail map[point]bool) (headTail, map[point]bool) {
  89. switch action.direction {
  90. case 'R':
  91. return moveRight(tracker, trail, action.steps)
  92. case 'L':
  93. return moveLeft(tracker, trail, action.steps)
  94. case 'U':
  95. return moveUp(tracker, trail, action.steps)
  96. case 'D':
  97. return moveDown(tracker, trail, action.steps)
  98. }
  99. return tracker, trail
  100. }
  101. func part1(moves []move) int {
  102. var tracker headTail
  103. trail := make(map[point]bool)
  104. trail[tracker.tail] = true
  105. for i := range moves {
  106. tracker, trail = drawTail(tracker, moves[i], trail)
  107. }
  108. return len(trail)
  109. }
  110. func main() {
  111. if len(os.Args) < 2 {
  112. log.Fatal("You need to specify a file!")
  113. }
  114. filePath := os.Args[1]
  115. file, err := os.Open(filePath)
  116. if err != nil {
  117. log.Fatalf("Failed to open %s!\n", filePath)
  118. }
  119. moves := readInput(file)
  120. fmt.Println("Part1:", part1(moves))
  121. }