code.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. )
  8. type Pattern struct {
  9. note [][]byte
  10. vertical int
  11. horizontal int
  12. }
  13. func readInput(file *os.File) []Pattern {
  14. scanner := bufio.NewScanner(file)
  15. var patterns []Pattern
  16. var current Pattern
  17. for scanner.Scan() {
  18. line := scanner.Text()
  19. if line == "" {
  20. patterns = append(patterns, current)
  21. current = Pattern{}
  22. continue
  23. }
  24. var row []byte
  25. for i := range line {
  26. row = append(row, line[i])
  27. }
  28. current.note = append(current.note, row)
  29. }
  30. patterns = append(patterns, current)
  31. return patterns
  32. }
  33. func checkVertical(index int, note [][]byte, width int, canMissOne bool) bool {
  34. left := 0
  35. prev := index - 1
  36. right := index + prev
  37. if right >= width {
  38. right = width - 1
  39. }
  40. for {
  41. if prev < left || index > right {
  42. break
  43. }
  44. for i := range note {
  45. if note[i][prev] != note[i][index] {
  46. if canMissOne {
  47. canMissOne = false
  48. continue
  49. }
  50. return false
  51. }
  52. }
  53. prev--
  54. index++
  55. }
  56. return true
  57. }
  58. func checkHorizontal(index int, note [][]byte, height int, width int, canMissOne bool) bool {
  59. up := 0
  60. prev := index - 1
  61. down := index + prev
  62. if down >= height {
  63. down = height - 1
  64. }
  65. for {
  66. if prev < up || index > down {
  67. break
  68. }
  69. for i := range note[index] {
  70. if note[index][i] != note[prev][i] {
  71. if canMissOne {
  72. canMissOne = false
  73. continue
  74. }
  75. return false
  76. }
  77. }
  78. prev--
  79. index++
  80. }
  81. return true
  82. }
  83. func parts(patterns []Pattern, canMissOne bool) int {
  84. var result int
  85. for i := range patterns {
  86. width := len(patterns[i].note[0])
  87. height := len(patterns[i].note)
  88. vertical := 0
  89. for index := 1; index < width; index++ {
  90. if index == patterns[i].vertical {
  91. continue
  92. }
  93. if checkVertical(index, patterns[i].note, width, canMissOne) {
  94. vertical = index
  95. patterns[i].vertical = index
  96. break
  97. }
  98. }
  99. horizontal := 0
  100. for index := 1; index < height; index++ {
  101. if index == patterns[i].horizontal {
  102. continue
  103. }
  104. if checkHorizontal(index, patterns[i].note, height, width, canMissOne) {
  105. horizontal = index
  106. patterns[i].horizontal = index
  107. break
  108. }
  109. }
  110. if horizontal > 0 {
  111. result += horizontal * 100
  112. } else if vertical > 0 {
  113. result += vertical
  114. }
  115. }
  116. return result
  117. }
  118. func main() {
  119. if len(os.Args) < 2 {
  120. log.Fatal("You need to specify a file!")
  121. }
  122. filePath := os.Args[1]
  123. file, err := os.Open(filePath)
  124. if err != nil {
  125. log.Fatalf("Failed to open %s!\n", filePath)
  126. }
  127. patterns := readInput(file)
  128. fmt.Println("Part1:", parts(patterns, false))
  129. fmt.Println("Part2:", parts(patterns, true))
  130. }