123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- package main
- import (
- "bufio"
- "fmt"
- "log"
- "os"
- "strconv"
- "strings"
- )
- func readNumbers(line string) []int {
- var numbers []int
- numbersStrings := strings.Split(line, ",")
- for _, numberString := range numbersStrings {
- if number, err := strconv.Atoi(numberString); err == nil {
- numbers = append(numbers, number)
- } else {
- log.Fatal("Numbers: ", err)
- }
- }
- return numbers
- }
- func readRow(line string) []int {
- var numbers []int
- numbersStrings := strings.Split(line, " ")
- for _, numberString := range numbersStrings {
- if numberString == "" {
- continue
- }
- if number, err := strconv.Atoi(numberString); err == nil {
- numbers = append(numbers, number)
- } else {
- log.Fatal("Row: ", err, numberString)
- }
- }
- return numbers
- }
- type Number struct {
- Val int
- Marked bool
- }
- func readInput(file *os.File) ([][][]Number, []int) {
- scanner := bufio.NewScanner(file)
- numbersRead := false
- var numbers []int
- var boards [][][]Number
- boardIndex := 0
- rowIndex := 0
- for scanner.Scan() {
- line := scanner.Text()
- if line == "" {
- continue
- }
- if !numbersRead {
- numbers = readNumbers(line)
- numbersRead = true
- continue
- }
- if rowIndex == 0 {
- boards = append(boards, make([][]Number, 5))
- }
- boards[boardIndex][rowIndex] = make([]Number, 5)
- numbersInRow := readRow(line)
- for i, number := range numbersInRow {
- boards[boardIndex][rowIndex][i] = Number{number, false}
- }
- rowIndex++
- if rowIndex > 4 {
- rowIndex = 0
- boardIndex++
- }
- }
- if err := scanner.Err(); err != nil {
- log.Fatalf("Scanner error: %s", err)
- }
- return boards, numbers
- }
- func allTrue(slice []bool) bool {
- for _, value := range slice {
- if !value {
- return false
- }
- }
- return true
- }
- func checkWinner(board [][]Number, row int, col int) bool {
- rowCheck := make([]bool, 5)
- for i := 0; i < 5; i++ {
- rowCheck[i] = board[row][i].Marked
- }
- if allTrue(rowCheck) {
- return true
- }
- colCheck := make([]bool, 5)
- for i := 0; i < 5; i++ {
- colCheck[i] = board[i][col].Marked
- }
- return allTrue(colCheck)
- }
- func mark(boards [][][]Number, number int) *[][]Number {
- var winner *[][]Number
- for _, board := range boards {
- for i, row := range board {
- for j, _ := range row {
- if row[j].Val == number {
- row[j].Marked = true
- if checkWinner(board, i, j) {
- winner = &board
- }
- }
- }
- }
- }
- return winner
- }
- func calculateBoard(board *[][]Number) int {
- sum := 0
- for _, row := range *board {
- for _, number := range row {
- if !number.Marked {
- sum += number.Val
- }
- }
- }
- return sum
- }
- func part1(boards [][][]Number, numbers []int) int {
- lastNumber := 0
- sumOfUnmarkedNumbers := 0
- for _, number := range numbers {
- lastNumber = number
- winner := mark(boards, number)
- if winner != nil {
- sumOfUnmarkedNumbers = calculateBoard(winner)
- break
- }
- }
- return lastNumber * sumOfUnmarkedNumbers
- }
- func isWinner(boardIndex int, winners []int) bool {
- for _, winner := range winners {
- if boardIndex == winner {
- return true
- }
- }
- return false
- }
- func mark2(boards [][][]Number, number int, winners []int) (bool, []int) {
- newWinner := false
- for x, board := range boards {
- if isWinner(x, winners) {
- continue
- }
- for i, row := range board {
- for j, _ := range row {
- if row[j].Val == number {
- row[j].Marked = true
- if checkWinner(board, i, j) {
- winners = append(winners, x)
- newWinner = true
- }
- }
- }
- }
- }
- return newWinner, winners
- }
- func part2(boards [][][]Number, numbers []int) int {
- lastNumber := 0
- var winners []int
- newWinner := false
- for _, number := range numbers {
- newWinner, winners = mark2(boards, number, winners)
- if newWinner {
- lastNumber = number
- }
- }
- return lastNumber * calculateBoard(&boards[winners[len(winners)-1]])
- }
- func main() {
- if len(os.Args) < 2 {
- log.Fatal("You need to specify a file!")
- }
- filePath := os.Args[1]
- file, err := os.Open(filePath)
- if err != nil {
- log.Fatalf("Failed to open %s!\n", filePath)
- }
- boards, numbers := readInput(file)
- fmt.Println("Part 1: ", part1(boards, numbers))
- _, err = file.Seek(0, 0)
- if err != nil {
- log.Fatal("Seek: ", err)
- }
- boards, numbers = readInput(file)
- fmt.Println("Part 2: ", part2(boards, numbers))
- }
|