code.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "log"
  6. "os"
  7. "sort"
  8. "strings"
  9. )
  10. func readInput(file string) []string {
  11. content, err := ioutil.ReadFile(file)
  12. if err != nil {
  13. log.Fatal(err)
  14. }
  15. lines := strings.Split(string(content), "\n")
  16. return lines
  17. }
  18. var points map[rune]int
  19. func init() {
  20. points = make(map[rune]int)
  21. points[')'] = 3
  22. points[']'] = 57
  23. points['}'] = 1197
  24. points['>'] = 25137
  25. }
  26. func parseLine(line string) rune {
  27. var lastOpened []rune
  28. for _, char := range line {
  29. if char == '(' || char == '[' || char == '{' || char == '<' {
  30. lastOpened = append(lastOpened, char)
  31. continue
  32. }
  33. if len(lastOpened) == 0 {
  34. return char
  35. }
  36. switch char {
  37. case ')':
  38. if lastOpened[len(lastOpened)-1] != '(' {
  39. return char
  40. }
  41. case ']':
  42. if lastOpened[len(lastOpened)-1] != '[' {
  43. return char
  44. }
  45. case '}':
  46. if lastOpened[len(lastOpened)-1] != '{' {
  47. return char
  48. }
  49. case '>':
  50. if lastOpened[len(lastOpened)-1] != '<' {
  51. return char
  52. }
  53. }
  54. lastOpened = lastOpened[:len(lastOpened)-1]
  55. }
  56. return ' '
  57. }
  58. func part1(input []string) (int, []string) {
  59. var total int
  60. var incomplete []string
  61. for _, line := range input {
  62. illegal := parseLine(line)
  63. if illegal != ' ' {
  64. total += points[illegal]
  65. continue
  66. }
  67. incomplete = append(incomplete, line)
  68. }
  69. return total, incomplete
  70. }
  71. func fixLine(line string) []rune {
  72. var lastOpened []rune
  73. for _, char := range line {
  74. if char == '(' || char == '[' || char == '{' || char == '<' {
  75. lastOpened = append(lastOpened, char)
  76. continue
  77. }
  78. if len(lastOpened) == 0 {
  79. return lastOpened
  80. }
  81. switch char {
  82. case ')':
  83. if lastOpened[len(lastOpened)-1] == '(' {
  84. lastOpened = lastOpened[:len(lastOpened)-1]
  85. }
  86. case ']':
  87. if lastOpened[len(lastOpened)-1] == '[' {
  88. lastOpened = lastOpened[:len(lastOpened)-1]
  89. }
  90. case '}':
  91. if lastOpened[len(lastOpened)-1] == '{' {
  92. lastOpened = lastOpened[:len(lastOpened)-1]
  93. }
  94. case '>':
  95. if lastOpened[len(lastOpened)-1] == '<' {
  96. lastOpened = lastOpened[:len(lastOpened)-1]
  97. }
  98. }
  99. }
  100. return lastOpened
  101. }
  102. func calculateScore(line []rune) int {
  103. var score int
  104. max := len(line)
  105. for i := max - 1; i >= 0; i-- {
  106. score *= 5
  107. switch line[i] {
  108. case '(':
  109. score += 1
  110. case '[':
  111. score += 2
  112. case '{':
  113. score += 3
  114. case '<':
  115. score += 4
  116. }
  117. }
  118. return score
  119. }
  120. func part2(input []string) int {
  121. var scores []int
  122. for _, line := range input {
  123. toFix := fixLine(line)
  124. scores = append(scores, calculateScore(toFix))
  125. }
  126. sort.Ints(scores)
  127. return scores[len(scores)/2]
  128. }
  129. func main() {
  130. if len(os.Args) < 2 {
  131. log.Fatal("Please provide a file name as argument")
  132. }
  133. input := readInput(os.Args[1])
  134. total, incomplete := part1(input)
  135. fmt.Println("Part 1:", total)
  136. fmt.Println("Part 2:", part2(incomplete))
  137. }