mirror of
https://github.com/RussellChamp/advent-of-code-2021.git
synced 2026-10-27 21:52:32 +00:00
day 4
This commit is contained in:
1 parent
32827d0602
commit
daefcfd70b
2 files changed
+282
No files matched your search
+271
@@ -0,0 +1,271 @@
|
||||
/* Day 4: Giant Squid */
|
||||
// TODO: Redo this whole thing with bit arrays instead
|
||||
package main
|
||||
|
||||
import (
|
||||
"AoC2021/utils/timer"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func check(e error) {
|
||||
if e != nil {
|
||||
fmt.Println("Oh snap!")
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("--- Day 4: Giant Squid ---")
|
||||
timer.Start()
|
||||
part1()
|
||||
timer.Tick()
|
||||
fmt.Println()
|
||||
|
||||
part2()
|
||||
timer.Tick()
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
type Card = [][]string
|
||||
|
||||
func readData(input *os.File) ([]string, []Card) {
|
||||
scanner := bufio.NewScanner(input)
|
||||
|
||||
var draws []string
|
||||
|
||||
if scanner.Scan() {
|
||||
draws = strings.Split(scanner.Text(), ",")
|
||||
}
|
||||
|
||||
var cards []Card
|
||||
cardIdx := -1 // the first new line will initialize card 0
|
||||
rowIdx := 0
|
||||
|
||||
// fmt.Printf("Created cards %s", cards)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
switch {
|
||||
case line == "": // when we hit an epty line, initialize a new card
|
||||
cards = append(cards, Card{})
|
||||
cardIdx += 1
|
||||
rowIdx = 0
|
||||
//fmt.Printf("Added card %d to cards {%s}\n", cardIdx, cards)
|
||||
default:
|
||||
rowVals := strings.Fields(line)
|
||||
//fmt.Printf("Attempting to push [%s] to card %d row %d {%s}\n", line, cardIdx, rowIdx, cards[cardIdx])
|
||||
cards[cardIdx] = append(cards[cardIdx], rowVals)
|
||||
rowIdx += 1
|
||||
}
|
||||
}
|
||||
|
||||
return draws, cards
|
||||
}
|
||||
|
||||
type MarkedCard = [][]bool
|
||||
|
||||
func initializeMarks(cards []Card) []MarkedCard {
|
||||
// create a number of marked cards equal to the number of bingo cards
|
||||
cardsLen := len(cards)
|
||||
marks := make([]MarkedCard, cardsLen)
|
||||
// find the number of rows on a card
|
||||
rowCount := len(cards[0])
|
||||
colCount := len(cards[0][0])
|
||||
|
||||
for cIdx := 0; cIdx < cardsLen; cIdx++ {
|
||||
marks[cIdx] = make([][]bool, rowCount)
|
||||
for rIdx := 0; rIdx < rowCount; rIdx++ {
|
||||
//fmt.Printf("Attempting to add row %d to card %d", rIdx, cIdx)
|
||||
//fmt.Println(marks[cIdx])
|
||||
marks[cIdx][rIdx] = make([]bool, colCount)
|
||||
}
|
||||
}
|
||||
|
||||
return marks
|
||||
}
|
||||
|
||||
func markCards(cards []Card, marks []MarkedCard, draw string) []MarkedCard {
|
||||
for cIdx, card := range cards {
|
||||
for rowIdx, row := range card {
|
||||
for colIdx, value := range row {
|
||||
if value == draw {
|
||||
marks[cIdx][rowIdx][colIdx] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return marks
|
||||
}
|
||||
|
||||
// TODO: currently assumes only one card will win per round
|
||||
func findWinningCardIdx(marks []MarkedCard) int {
|
||||
for cIdx, card := range marks {
|
||||
if matchesRow(card) || matchesColumn(card) {
|
||||
return cIdx
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func matchesRow(card MarkedCard) bool {
|
||||
for _, row := range card {
|
||||
marks := 0
|
||||
for _, value := range row {
|
||||
if value {
|
||||
marks += 1
|
||||
}
|
||||
}
|
||||
if marks == len(row) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func matchesColumn(card MarkedCard) bool {
|
||||
rowCount := len(card)
|
||||
colCount := len(card[0])
|
||||
for colIdx := 0; colIdx < colCount; colIdx++ {
|
||||
marks := 0
|
||||
for rowIdx := 0; rowIdx < rowCount; rowIdx++ {
|
||||
if card[rowIdx][colIdx] {
|
||||
marks += 1
|
||||
}
|
||||
}
|
||||
|
||||
if marks == colCount {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getCardScore(card Card, mark MarkedCard) int {
|
||||
score := 0
|
||||
|
||||
// sum up all the non-marked bingo spots
|
||||
for rIdx, row := range card {
|
||||
for cIdx, strVal := range row {
|
||||
if !mark[rIdx][cIdx] {
|
||||
value, err := strconv.Atoi(strVal)
|
||||
check(err)
|
||||
|
||||
score += value
|
||||
}
|
||||
}
|
||||
}
|
||||
return score
|
||||
}
|
||||
|
||||
func part1() {
|
||||
fmt.Println("* Part 1 *")
|
||||
fmt.Println(" Goal: Figure out which bingo board will win first.")
|
||||
fmt.Println(" Answer: What will your final score be if you choose that board?")
|
||||
|
||||
input, err := os.Open("./input.txt")
|
||||
check(err)
|
||||
defer input.Close()
|
||||
|
||||
draws, cards := readData(input)
|
||||
marks := initializeMarks(cards)
|
||||
|
||||
//fmt.Printf("Read in %d draws and %d cards\n", len(draws), len(cards))
|
||||
//fmt.Printf("Initialized %d mark cards\n", len(marks))
|
||||
//fmt.Printf("First card %s\n", cards[0])
|
||||
//fmt.Println(marks[0])
|
||||
|
||||
drawTimes := 0
|
||||
winningCardIdx := -1
|
||||
lastDraw := 0
|
||||
score := 0
|
||||
for _, draw := range draws {
|
||||
drawTimes += 1
|
||||
marks = markCards(cards, marks, draw)
|
||||
winningCardIdx = findWinningCardIdx(marks)
|
||||
if winningCardIdx >= 0 {
|
||||
winningCard := cards[winningCardIdx]
|
||||
winningMarks := marks[winningCardIdx]
|
||||
score = getCardScore(winningCard, winningMarks)
|
||||
|
||||
// multiply by the last drawn tile
|
||||
mult, err := strconv.Atoi(draw)
|
||||
check(err)
|
||||
|
||||
lastDraw = mult
|
||||
score *= mult
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("After %d draws, card #%d won on a %d with a score of %d\n", drawTimes, winningCardIdx, lastDraw, score)
|
||||
}
|
||||
|
||||
func part2() {
|
||||
fmt.Println("* Part 2 *")
|
||||
fmt.Println(" Goal: Figure out which board will win last.")
|
||||
fmt.Println(" Answer: Once it wins, what would its final score be?")
|
||||
|
||||
input, err := os.Open("./input.txt")
|
||||
check(err)
|
||||
defer input.Close()
|
||||
|
||||
draws, cards := readData(input)
|
||||
marks := initializeMarks(cards)
|
||||
|
||||
drawTimes := 0
|
||||
lastDraw := 0
|
||||
score := 0
|
||||
foundLoser := false
|
||||
|
||||
for _, draw := range draws {
|
||||
if foundLoser {
|
||||
break
|
||||
}
|
||||
|
||||
drawTimes += 1
|
||||
marks = markCards(cards, marks, draw)
|
||||
winningCardIdx := findWinningCardIdx(marks)
|
||||
|
||||
eliminatedCards := 0
|
||||
for winningCardIdx > -1 {
|
||||
// if there's only one card left, it's the losingist one
|
||||
if len(marks) == 1 {
|
||||
score = getCardScore(cards[0], marks[0])
|
||||
|
||||
// multiply by the last drawn tile
|
||||
mult, err := strconv.Atoi(draw)
|
||||
check(err)
|
||||
|
||||
lastDraw = mult
|
||||
score *= mult
|
||||
foundLoser = true
|
||||
break
|
||||
}
|
||||
|
||||
eliminatedCards += 1
|
||||
// if a card wins, just remove it from the list of cards and don't track it anymore
|
||||
cards[winningCardIdx] = cards[len(cards)-1]
|
||||
cards[len(cards)-1] = Card{}
|
||||
cards = cards[:len(cards)-1]
|
||||
|
||||
marks[winningCardIdx] = marks[len(marks)-1]
|
||||
marks[len(marks)-1] = MarkedCard{}
|
||||
marks = marks[:len(marks)-1]
|
||||
|
||||
winningCardIdx = findWinningCardIdx(marks)
|
||||
}
|
||||
if eliminatedCards > 0 {
|
||||
//fmt.Printf("Round %d: Eliminated %d cards with a %s (%d remaining)\n", drawTimes, eliminatedCards, draw, len(cards))
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Println("Card: ", cards[0])
|
||||
//fmt.Println("Mark: ", marks[0])
|
||||
fmt.Printf("After %d draws, the losingist card won on a %d with a score of %d\n", drawTimes, lastDraw, score)
|
||||
}
|
||||
Reference in new issue
Block a user