code.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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. var winner *[][]Number
  101. for _, board := range boards {
  102. for i, row := range board {
  103. for j, _ := range row {
  104. if row[j].Val == number {
  105. row[j].Marked = true
  106. if checkWinner(board, i, j) {
  107. winner = &board
  108. }
  109. }
  110. }
  111. }
  112. }
  113. return winner
  114. }
  115. func calculateBoard(board *[][]Number) int {
  116. sum := 0
  117. for _, row := range *board {
  118. for _, number := range row {
  119. if !number.Marked {
  120. sum += number.Val
  121. }
  122. }
  123. }
  124. return sum
  125. }
  126. func part1(boards [][][]Number, numbers []int) int {
  127. lastNumber := 0
  128. sumOfUnmarkedNumbers := 0
  129. for _, number := range numbers {
  130. lastNumber = number
  131. winner := mark(boards, number)
  132. if winner != nil {
  133. sumOfUnmarkedNumbers = calculateBoard(winner)
  134. break
  135. }
  136. }
  137. return lastNumber * sumOfUnmarkedNumbers
  138. }
  139. func isWinner(boardIndex int, winners []int) bool {
  140. for _, winner := range winners {
  141. if boardIndex == winner {
  142. return true
  143. }
  144. }
  145. return false
  146. }
  147. func mark2(boards [][][]Number, number int, winners []int) (bool, []int) {
  148. newWinner := false
  149. for x, board := range boards {
  150. if isWinner(x, winners) {
  151. continue
  152. }
  153. for i, row := range board {
  154. for j, _ := range row {
  155. if row[j].Val == number {
  156. row[j].Marked = true
  157. if checkWinner(board, i, j) {
  158. winners = append(winners, x)
  159. newWinner = true
  160. }
  161. }
  162. }
  163. }
  164. }
  165. return newWinner, winners
  166. }
  167. func part2(boards [][][]Number, numbers []int) int {
  168. lastNumber := 0
  169. var winners []int
  170. newWinner := false
  171. for _, number := range numbers {
  172. newWinner, winners = mark2(boards, number, winners)
  173. if newWinner {
  174. lastNumber = number
  175. }
  176. }
  177. return lastNumber * calculateBoard(&boards[winners[len(winners)-1]])
  178. }
  179. func main() {
  180. if len(os.Args) < 2 {
  181. log.Fatal("You need to specify a file!")
  182. }
  183. filePath := os.Args[1]
  184. file, err := os.Open(filePath)
  185. if err != nil {
  186. log.Fatalf("Failed to open %s!\n", filePath)
  187. }
  188. boards, numbers := readInput(file)
  189. fmt.Println("Part 1: ", part1(boards, numbers))
  190. _, err = file.Seek(0, 0)
  191. if err != nil {
  192. log.Fatal("Seek: ", err)
  193. }
  194. boards, numbers = readInput(file)
  195. fmt.Println("Part 2: ", part2(boards, numbers))
  196. }