day 4 in the books
This commit is contained in:
parent
9bccec439e
commit
77170d40b9
195
04/main.go
Normal file
195
04/main.go
Normal file
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user