From 77170d40b9ee8b2fd935c14a6b7ecb4f054a0248 Mon Sep 17 00:00:00 2001 From: David Ashby Date: Sat, 4 Dec 2021 10:38:03 -0500 Subject: [PATCH] day 4 in the books --- 04/main.go | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 04/main.go diff --git a/04/main.go b/04/main.go new file mode 100644 index 0000000..8eb6c0f --- /dev/null +++ b/04/main.go @@ -0,0 +1,195 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" + "time" +) + +func main() { + start := time.Now() + partOne() + duration := time.Since(start) + partTwo() + duration2 := time.Since(start) + fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration) +} + +func makeScanner(test bool) *bufio.Scanner { + var f *os.File + if test { + f, _ = os.Open("inputs/testinput") + } else { + f, _ = os.Open("inputs/input") + } + reader := bufio.NewReader(f) + return bufio.NewScanner(reader) +} + +func mustAtoi(line string) int { + i, err := strconv.Atoi(line) + if err != nil { + panic(err) + } + return i +} + +func convertDraws(d []string) []int { + r := make([]int, len(d)) + for i := range d { + r[i] = mustAtoi(d[i]) + } + return r +} + +func contains(i int, a []int) bool { + for _, j := range a { + if i == j { + return true + } + } + return false +} + +// a bingo card like this: +// 60 79 46 9 58 +// 97 81 6 94 84 +// 38 40 17 61 29 +// 11 28 0 91 15 +// 24 77 34 59 36 +// turns into this: +// rows: [][60 79 46 9 58][97 81 6 94 84]... +// columns: [][60 97 38 11 24][79 81 40 28 77]... +// so that checking all possible hits is easier +// we use maps and not arrays to also make the lookups quicker + +type bingoCard struct { + allNumbers []int + rows []map[int]struct{} + columns []map[int]struct{} + winner bool +} + +func readBingoCard(scanner *bufio.Scanner) bingoCard { + card := bingoCard{ + allNumbers: make([]int, 0), + rows: make([]map[int]struct{}, 5), + columns: make([]map[int]struct{}, 5), + } + // what a pain + card.rows[0] = make(map[int]struct{}) + card.rows[1] = make(map[int]struct{}) + card.rows[2] = make(map[int]struct{}) + card.rows[3] = make(map[int]struct{}) + card.rows[4] = make(map[int]struct{}) + card.columns[0] = make(map[int]struct{}) + card.columns[1] = make(map[int]struct{}) + card.columns[2] = make(map[int]struct{}) + card.columns[3] = make(map[int]struct{}) + card.columns[4] = make(map[int]struct{}) + + for i := 0; i < 5; i++ { + scanner.Scan() + row := strings.Split(scanner.Text(), " ") + var col int + for _, p := range row { + if p != "" { + num := mustAtoi(p) + card.allNumbers = append(card.allNumbers, num) + card.rows[i][num] = struct{}{} + card.columns[col][num] = struct{}{} + col++ + } + } + } + return card +} + +func checkBoard(currentNumbers []int, card bingoCard) bool { + for _, row := range card.rows { + hits := 0 + for _, i := range currentNumbers { + if _, ok := row[i]; ok { + hits++ + } + } + if hits == 5 { + return true + } + } + for _, col := range card.columns { + hits := 0 + for _, i := range currentNumbers { + if _, ok := col[i]; ok { + hits++ + } + } + if hits == 5 { + return true + } + } + return false +} + +func scoreBoard(currentNumbers []int, card bingoCard) int { + totalUncalled := 0 + for _, i := range card.allNumbers { + if !contains(i, currentNumbers) { + totalUncalled += i + } + } + return totalUncalled * currentNumbers[len(currentNumbers)-1] +} + +func partOne() { + scanner := makeScanner(false) + + scanner.Scan() + draws := convertDraws(strings.Split(scanner.Text(), ",")) + cards := []bingoCard{} + + for scanner.Scan() { + cards = append(cards, readBingoCard(scanner)) + } + for i := range draws { + for _, card := range cards { + winner := checkBoard(draws[0:i], card) + if winner { + fmt.Println(scoreBoard(draws[0:i], card)) + return + } + } + } +} + +func partTwo() { + scanner := makeScanner(false) + + scanner.Scan() + draws := convertDraws(strings.Split(scanner.Text(), ",")) + cards := []bingoCard{} + + for scanner.Scan() { + cards = append(cards, readBingoCard(scanner)) + } + + winnerCount := 0 + for i := range draws { + for j, card := range cards { + if !card.winner { + winner := checkBoard(draws[0:i], card) + if winner { + cards[j].winner = true + winnerCount++ + if winnerCount == len(cards) { + // that was the last one! + fmt.Println(scoreBoard(draws[0:i], card)) + } + } + } + } + } +}