2021-12-04 14:48:05 +01:00
package main
import (
"AOC2021/src/helper"
"fmt"
"os"
"strings"
)
type bingoField struct {
number int
checked bool
}
type bingoGame struct {
winState [ ] int
currentRound int
numbers [ ] int
boards [ ] [ ] [ ] bingoField
}
func main ( ) {
args := os . Args [ 1 : ]
input , err := helper . GetInput ( args [ 0 ] )
if err != nil {
fmt . Println ( err )
}
bingoNumbers , _ := helper . MapToNumber ( strings . Split ( input [ 0 ] , "," ) )
bingoBoards := parseBoards ( input )
part1 ( bingoNumbers , bingoBoards )
part2 ( bingoNumbers , bingoBoards )
}
func part1 ( bingoNumbers [ ] int , bingoBoards [ ] [ ] [ ] bingoField ) {
game := bingoGame { [ ] int { } , 0 , bingoNumbers , bingoBoards }
for len ( game . winState ) == 0 {
game . playRound ( )
}
fmt . Println ( getSumOfUncheckedField ( game . boards [ game . winState [ 0 ] ] ) * game . numbers [ game . currentRound - 1 ] )
}
func part2 ( bingoNumbers [ ] int , bingoBoards [ ] [ ] [ ] bingoField ) {
game := bingoGame { [ ] int { } , 0 , bingoNumbers , bingoBoards }
for len ( game . winState ) < len ( game . boards ) {
game . playRound ( )
}
fmt . Println ( getSumOfUncheckedField ( game . boards [ game . winState [ len ( game . winState ) - 1 ] ] ) * game . numbers [ game . currentRound - 1 ] )
}
func parseBoards ( input [ ] string ) [ ] [ ] [ ] bingoField {
var bingoBoards [ ] [ ] [ ] bingoField
for i := 0 ; i * 6 + 6 <= len ( input ) ; i ++ {
begin := 2 + i * 6
end := 7 + i * 6
bingoBoards = append ( bingoBoards , parseBoard ( input [ begin : end ] ) )
}
return bingoBoards
}
func parseBoard ( input [ ] string ) [ ] [ ] bingoField {
bingoBoard := make ( [ ] [ ] bingoField , len ( input ) )
for i , line := range input {
numberStrings := strings . Split ( line , " " )
2021-12-12 16:15:16 +01:00
numberStrings = helper . RemoveElementFromStringArray ( numberStrings , "" )
2021-12-04 14:48:05 +01:00
numbers , _ := helper . MapToNumber ( numberStrings )
row := make ( [ ] bingoField , len ( numbers ) )
for i , number := range numbers {
row [ i ] = bingoField { number , false }
}
bingoBoard [ i ] = row
}
return bingoBoard
}
func ( game * bingoGame ) playRound ( ) {
drawnNumber := game . numbers [ game . currentRound ]
for _ , board := range game . boards {
markFields ( & board , drawnNumber )
}
for i , board := range game . boards {
if ! helper . Contains ( i , game . winState ) && checkWinCondition ( board ) {
game . winState = append ( game . winState , i )
}
}
game . currentRound ++
}
func markFields ( board * [ ] [ ] bingoField , drawnNumber int ) {
for i , row := range * board {
for j , field := range row {
if field . number == drawnNumber {
( * board ) [ i ] [ j ] = bingoField { drawnNumber , true }
}
}
}
}
func checkWinCondition ( board [ ] [ ] bingoField ) bool {
winConditionBoard := make ( [ ] [ ] int , len ( board ) )
for i , row := range board {
for _ , field := range row {
if field . checked {
winConditionBoard [ i ] = append ( winConditionBoard [ i ] , 1 )
} else {
winConditionBoard [ i ] = append ( winConditionBoard [ i ] , 0 )
}
}
}
if checkWinConditionRows ( winConditionBoard ) || checkWinConditionRows ( helper . Transpose ( winConditionBoard ) ) {
return true
}
return false
}
func checkWinConditionRows ( rows [ ] [ ] int ) bool {
for _ , row := range rows {
if helper . AddNummbers ( row ... ) == len ( row ) {
return true
}
}
return false
}
func checkWinConditionDiagonals ( rows [ ] [ ] int ) bool {
return checkWinConditionDiagonal ( rows ) || checkWinConditionDiagonalInverse ( rows )
}
func checkWinConditionDiagonal ( rows [ ] [ ] int , ) bool {
for i := 0 ; i < len ( rows ) ; i ++ {
if rows [ i ] [ i ] == 0 {
return false
}
}
return true
}
func checkWinConditionDiagonalInverse ( rows [ ] [ ] int ) bool {
for i := 0 ; i < len ( rows ) ; i ++ {
if rows [ 4 - i ] [ i ] == 0 {
return false
}
}
return true
}
func getSumOfUncheckedField ( board [ ] [ ] bingoField ) int {
sum := 0
for _ , row := range board {
for _ , field := range row {
if ! field . checked {
sum += field . number
}
}
}
return sum
}