code.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. "strconv"
  8. "strings"
  9. )
  10. func readNumbers(line string) []int {
  11. var numbers []int
  12. numbersStrings := strings.Split(line, ",")
  13. for _, numberString := range numbersStrings {
  14. if number, err := strconv.Atoi(numberString); err == nil {
  15. numbers = append(numbers, number)
  16. } else {
  17. log.Fatal("Numbers: ", err)
  18. }
  19. }
  20. return numbers
  21. }
  22. func readRow(line string) []int {
  23. var numbers []int
  24. numbersStrings := strings.Split(line, " ")
  25. for _, numberString := range numbersStrings {
  26. if numberString == "" {
  27. continue
  28. }
  29. if number, err := strconv.Atoi(numberString); err == nil {
  30. numbers = append(numbers, number)
  31. } else {
  32. log.Fatal("Row: ", err, numberString)
  33. }
  34. }
  35. return numbers
  36. }
  37. type Number struct {
  38. Val int
  39. Marked bool
  40. }
  41. func readInput(file *os.File) ([][][]Number, []int) {
  42. scanner := bufio.NewScanner(file)
  43. numbersRead := false
  44. var numbers []int
  45. var boards [][][]Number
  46. boardIndex := 0
  47. rowIndex := 0
  48. for scanner.Scan() {
  49. line := scanner.Text()
  50. if line == "" {
  51. continue
  52. }
  53. if !numbersRead {
  54. numbers = readNumbers(line)
  55. numbersRead = true
  56. continue
  57. }
  58. if rowIndex == 0 {
  59. boards = append(boards, make([][]Number, 5))
  60. }
  61. boards[boardIndex][rowIndex] = make([]Number, 5)
  62. numbersInRow := readRow(line)
  63. for i, number := range numbersInRow {
  64. boards[boardIndex][rowIndex][i] = Number{number, false}
  65. }
  66. rowIndex++
  67. if rowIndex > 4 {
  68. rowIndex = 0
  69. boardIndex++
  70. }
  71. }
  72. if err := scanner.Err(); err != nil {
  73. log.Fatalf("Scanner error: %s", err)
  74. }
  75. return boards, numbers
  76. }
  77. func allTrue(slice []bool) bool {
  78. for _, value := range slice {
  79. if !value {
  80. return false
  81. }
  82. }
  83. return true
  84. }
  85. func checkWinner(board [][]Number, row int, col int) bool {
  86. rowCheck := make([]bool, 5)
  87. for i := 0; i < 5; i++ {
  88. rowCheck[i] = board[row][i].Marked
  89. }
  90. if allTrue(rowCheck) {
  91. return true
  92. }
  93. colCheck := make([]bool, 5)
  94. for i := 0; i < 5; i++ {
  95. colCheck[i] = board[i][col].Marked
  96. }
  97. return allTrue(colCheck)
  98. }
  99. func mark(boards [][][]Number, number int) *[][]Number {
  100. for _, board := range boards {
  101. for i, row := range board {
  102. for j, _ := range row {
  103. if row[j].Val == number {
  104. row[j].Marked = true
  105. if checkWinner(board, i, j) {
  106. return &board
  107. }
  108. }
  109. }
  110. }
  111. }
  112. return nil
  113. }
  114. func calculateBoard(board *[][]Number) int {
  115. sum := 0
  116. for _, row := range *board {
  117. for _, number := range row {
  118. if !number.Marked {
  119. sum += number.Val
  120. }
  121. }
  122. }
  123. return sum
  124. }
  125. func part1(boards [][][]Number, numbers []int) int {
  126. lastNumber := 0
  127. sumOfUnmarkedNumbers := 0
  128. for _, number := range numbers {
  129. lastNumber = number
  130. winner := mark(boards, number)
  131. if winner != nil {
  132. sumOfUnmarkedNumbers = calculateBoard(winner)
  133. break
  134. }
  135. }
  136. return lastNumber * sumOfUnmarkedNumbers
  137. }
  138. func main() {
  139. if len(os.Args) < 2 {
  140. log.Fatal("You need to specify a file!")
  141. }
  142. filePath := os.Args[1]
  143. file, err := os.Open(filePath)
  144. if err != nil {
  145. log.Fatalf("Failed to open %s!\n", filePath)
  146. }
  147. boards, numbers := readInput(file)
  148. fmt.Println("Part 1: ", part1(boards, numbers))
  149. }