code.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. )
  8. type Point struct {
  9. y, x int
  10. cost int
  11. cheats int
  12. }
  13. func (p *Point) key() string {
  14. return fmt.Sprintf("%d_%d", p.y, p.x)
  15. }
  16. func findPoint(line string, mark byte) *Point {
  17. for i := range line {
  18. if line[i] == mark {
  19. return &Point{x: i}
  20. }
  21. }
  22. return nil
  23. }
  24. func readInput(file *os.File) (*Point, [][]byte) {
  25. scanner := bufio.NewScanner(file)
  26. var matrix [][]byte
  27. var start *Point
  28. var y int
  29. for scanner.Scan() {
  30. line := scanner.Text()
  31. if line == "" {
  32. break
  33. }
  34. matrix = append(matrix, []byte(line))
  35. if start == nil {
  36. start = findPoint(line, 'S')
  37. if start != nil {
  38. start.y = y
  39. start.cheats = 2
  40. }
  41. }
  42. y++
  43. }
  44. return start, matrix
  45. }
  46. var directions [][]int = [][]int{
  47. {0, -1}, {1, 0}, {0, 1}, {-1, 0},
  48. }
  49. func getMoves(current Point, matrix [][]byte, xMax, yMax int, cheat bool) []Point {
  50. var moves []Point
  51. for _, direction := range directions {
  52. move := Point{x: current.x + direction[0], y: current.y + direction[1], cost: current.cost + 1, cheats: current.cheats}
  53. if move.x <= 0 || move.y <= 0 || move.x >= xMax || move.y >= yMax {
  54. continue
  55. }
  56. if matrix[move.y][move.x] == '#' {
  57. if cheat && move.cheats > 0 {
  58. move.cheats--
  59. moves = append(moves, move)
  60. }
  61. continue
  62. }
  63. if cheat && move.cheats == 1 {
  64. move.cheats = 0
  65. }
  66. moves = append(moves, move)
  67. }
  68. return moves
  69. }
  70. func hike(start *Point, matrix [][]byte, xMax, yMax int, cheat bool) int {
  71. cost := 1000000000
  72. visited := make(map[string]int)
  73. visited[start.key()] = start.cost
  74. moves := []Point{*start}
  75. for len(moves) > 0 {
  76. current := moves[0]
  77. moves = moves[1:]
  78. if matrix[current.y][current.x] == 'E' && current.cost < cost {
  79. cost = current.cost
  80. }
  81. newMoves := getMoves(current, matrix, xMax, yMax, cheat)
  82. for _, newMove := range newMoves {
  83. if visited[newMove.key()] == 0 || visited[newMove.key()] > newMove.cost {
  84. moves = append(moves, newMove)
  85. visited[newMove.key()] = newMove.cost
  86. }
  87. }
  88. }
  89. return cost
  90. }
  91. func part1(start *Point, matrix [][]byte) int {
  92. xMax := len(matrix[0]) - 1
  93. yMax := len(matrix) - 1
  94. bestWithoutCheating := hike(start, matrix, xMax, yMax, false)
  95. fmt.Println(bestWithoutCheating)
  96. return 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. start, matrix := readInput(file)
  108. fmt.Println("Part1:", part1(start, matrix))
  109. }