diff --git a/d4/d4.go b/d4/d4.go new file mode 100644 index 0000000..df19657 --- /dev/null +++ b/d4/d4.go @@ -0,0 +1,132 @@ +package d4 + +import ( + "strconv" + "strings" +) + +type cell struct { + value int + marked bool +} + +type board []cell + +const SIDE_SIZE = 5 + +func createBoards(rawBoards []string) []board { + boards := make([]board, len(rawBoards)) + + for i, rawBoard := range rawBoards { + for _, cellRow := range strings.Split(rawBoard, "\n") { + for _, rawCell := range strings.Split(cellRow, " ") { + if rawCell != "" { + value, _ := strconv.Atoi(rawCell) + boards[i] = append(boards[i], cell{value, false}) + } + } + } + } + + return boards +} + +func markBoard(b board, take int) board { + for i := range b { + if b[i].value == take { + b[i].marked = true + } + } + + return b +} + +func gotBingo(b board) bool { + + for i := 0; i < SIDE_SIZE; i++ { + if b[i*SIDE_SIZE].marked && + b[i*SIDE_SIZE+1].marked && + b[i*SIDE_SIZE+2].marked && + b[i*SIDE_SIZE+3].marked && + b[i*SIDE_SIZE+4].marked { + return true + } + } + + for j := 0; j < SIDE_SIZE; j++ { + if b[j].marked && + b[j+SIDE_SIZE].marked && + b[j+SIDE_SIZE*2].marked && + b[j+SIDE_SIZE*3].marked && + b[j+SIDE_SIZE*4].marked { + return true + } + } + + return false +} + +func findBingo(boards []board, takes []string) (board, int) { + + for _, take := range takes { + converted, _ := strconv.Atoi(take) + for _, board := range boards { + marked := markBoard(board, converted) + if gotBingo(marked) { + return marked, converted + } + } + } + + return nil, 0 +} + +func findBingo2(boards []board, takes []string) (board, int) { + bingos := make(map[*board]int) + wins := []*board{} + for _, take := range takes { + converted, _ := strconv.Atoi(take) + for boardIndex := range boards { + board := &boards[boardIndex] + if _, ok := bingos[board]; !ok { + marked := markBoard(*board, converted) + if gotBingo(marked) { + bingos[board] = converted + wins = append(wins, board) + } + } + } + } + + return *wins[len(wins)-1], bingos[wins[len(wins)-1]] +} + +func score(b board, take int) int { + sum := 0 + + for _, cell := range b { + if !cell.marked { + sum += cell.value + } + } + + return sum * take +} + +func D4(input string) int { + lines := strings.Split(input, "\n\n") + takes := strings.Split(lines[0], ",") + boards := createBoards(lines[1:]) + bingo, take := findBingo(boards, takes) + + return score(bingo, take) +} + +func D4P2(input string) int { + lines := strings.Split(input, "\n\n") + takes := strings.Split(lines[0], ",") + boards := createBoards(lines[1:]) + bingo, take := findBingo2(boards, takes) + + return score(bingo, take) +} diff --git a/d4/d4_test.go b/d4/d4_test.go new file mode 100644 index 0000000..aaae8bb --- /dev/null +++ b/d4/d4_test.go @@ -0,0 +1,57 @@ +package d4 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestD4(t *testing.T) { + input := `7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1 + +22 13 17 11 0 + 8 2 23 4 24 +21 9 14 16 7 + 6 10 3 18 5 + 1 12 20 15 19 + + 3 15 0 2 22 + 9 18 13 17 5 +19 8 7 25 23 +20 11 10 24 4 +14 21 16 12 6 + +14 21 17 24 4 +10 16 15 9 19 +18 8 23 26 20 +22 11 13 6 5 + 2 0 12 3 7 +` + + assert.EqualValues(t, 4512, D4(input)) +} + +func TestD4P2(t *testing.T) { + input := `7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1 + +22 13 17 11 0 + 8 2 23 4 24 +21 9 14 16 7 + 6 10 3 18 5 + 1 12 20 15 19 + + 3 15 0 2 22 + 9 18 13 17 5 +19 8 7 25 23 +20 11 10 24 4 +14 21 16 12 6 + +14 21 17 24 4 +10 16 15 9 19 +18 8 23 26 20 +22 11 13 6 5 + 2 0 12 3 7 +` + + assert.EqualValues(t, 1924, D4P2(input)) +} diff --git a/main.go b/main.go index 2bfbc9f..d53348b 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "github.com/fotonmoton/aoc2021/d1" "github.com/fotonmoton/aoc2021/d2" "github.com/fotonmoton/aoc2021/d3" + "github.com/fotonmoton/aoc2021/d4" ) func main() { @@ -28,5 +29,6 @@ func main() { fmt.Printf("day 2 part 2: %v\n", d2.D2P2(client.Day(2))) fmt.Printf("day 3: %v\n", d3.D3(client.Day(3))) fmt.Printf("day 3 part 2: %v\n", d3.D3P2(client.Day(3))) - + fmt.Printf("day 4: %v\n", d4.D4(client.Day(4))) + fmt.Printf("day 4 part 2: %v\n", d4.D4P2(client.Day(4))) }