code.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. )
  8. type Point struct {
  9. y, x int
  10. steps int
  11. }
  12. func (p Point) key() string {
  13. return fmt.Sprintf("%d_%d", p.y, p.x)
  14. }
  15. func readInput(file *os.File) []Point {
  16. scanner := bufio.NewScanner(file)
  17. var points []Point
  18. for scanner.Scan() {
  19. line := scanner.Text()
  20. if line == "" {
  21. break
  22. }
  23. var point Point
  24. n, err := fmt.Sscanf(line, "%d,%d", &point.x, &point.y)
  25. if n != 2 || err != nil {
  26. log.Fatalf("Not able to parse byte '%s': %s", line, err)
  27. }
  28. points = append(points, point)
  29. }
  30. return points
  31. }
  32. var directions [][]int = [][]int{
  33. {0, -1}, {1, 0}, {0, 1}, {-1, 0},
  34. }
  35. func getObstaclesMap(obstacles []Point, howMany, xMax, yMax int) map[string]bool {
  36. obstaclesMap := make(map[string]bool)
  37. for i := 0; i < howMany; i++ {
  38. if obstacles[i].x < xMax && obstacles[i].y < yMax {
  39. obstaclesMap[obstacles[i].key()] = true
  40. }
  41. }
  42. return obstaclesMap
  43. }
  44. func getMoves(current Point, obstaclesMap map[string]bool, xMax, yMax int) []Point {
  45. var moves []Point
  46. for _, direction := range directions {
  47. move := Point{x: current.x + direction[0], y: current.y + direction[1], steps: current.steps + 1}
  48. if move.x < 0 || move.y < 0 || move.x > xMax || move.y > yMax {
  49. continue
  50. }
  51. if !obstaclesMap[move.key()] {
  52. moves = append(moves, move)
  53. }
  54. }
  55. return moves
  56. }
  57. func hike(obstaclesMap map[string]bool, xMax, yMax int) int {
  58. steps := 1000000000
  59. visited := make(map[string]int)
  60. goal := Point{x: xMax, y: yMax}
  61. moves := []Point{Point{x: 0, y: 0}}
  62. for len(moves) > 0 {
  63. current := moves[0]
  64. moves = moves[1:]
  65. if current.x == goal.x && current.y == goal.y && current.steps < steps {
  66. steps = current.steps
  67. }
  68. newMoves := getMoves(current, obstaclesMap, xMax, yMax)
  69. for _, newMove := range newMoves {
  70. if visited[newMove.key()] == 0 || visited[newMove.key()] > newMove.steps {
  71. moves = append(moves, newMove)
  72. visited[newMove.key()] = newMove.steps
  73. }
  74. }
  75. }
  76. return steps
  77. }
  78. func part1(obstacles []Point, howMany, xMax, yMax int) int {
  79. obstaclesMap := getObstaclesMap(obstacles, howMany, xMax+1, yMax+1)
  80. return hike(obstaclesMap, xMax, yMax)
  81. }
  82. func addAnotherObstacle(obstaclesMap map[string]bool, xMax, yMax int, obstacles []Point, index int) {
  83. if obstacles[index].x < xMax && obstacles[index].y < yMax {
  84. obstaclesMap[obstacles[index].key()] = true
  85. }
  86. }
  87. func part2(obstacles []Point, howMany, xMax, yMax int) Point {
  88. obstaclesMap := getObstaclesMap(obstacles, howMany, xMax+1, yMax+1)
  89. edge := len(obstacles)
  90. for i := howMany + 1; i < edge; i++ {
  91. addAnotherObstacle(obstaclesMap, xMax+1, yMax+1, obstacles, i)
  92. if hike(obstaclesMap, xMax, yMax) == 1000000000 {
  93. return obstacles[i]
  94. }
  95. }
  96. return obstacles[0]
  97. }
  98. func main() {
  99. if len(os.Args) < 2 {
  100. log.Fatal("You need to specify a file!")
  101. }
  102. filePath := os.Args[1]
  103. file, err := os.Open(filePath)
  104. if err != nil {
  105. log.Fatalf("Failed to open %s!\n", filePath)
  106. }
  107. obstacles := readInput(file)
  108. fmt.Println("Part1:", part1(obstacles, 1024, 70, 70))
  109. badPoint := part2(obstacles, 1024, 70, 70)
  110. fmt.Println("Part2:", fmt.Sprintf("%d,%d", badPoint.x, badPoint.y))
  111. }