adventofcode/2023/day04/main.go

105 lines
1.9 KiB
Go

package main
import (
"fmt"
"math"
"strings"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
func main() {
inp := h.StdinToStringSlice()
part1(inp)
fmt.Println()
part2(inp)
}
func part1(input []string) {
var total int
for i := range input {
total += cardFromLine(input[i]).Value()
}
fmt.Println("# Part 1")
fmt.Println(total)
}
func part2(input []string) {
cards := make(map[int]*Card)
for i := range input {
c := cardFromLine(input[i])
cards[c.id] = c
}
result := len(cards)
for _, card := range cards {
result += card.TotalCardsWon(cards)
}
fmt.Println("# Part 2")
fmt.Println(result)
}
type Card struct {
id int
winners []int
numbers []int
winsCards []int
totalCardsWon int
}
func (c Card) String() string {
return fmt.Sprintf("Card %d: %v | %v", c.id, c.winners, c.numbers)
}
func cardFromLine(input string) *Card {
pts := strings.Fields(input)
ret := Card{id: h.Atoi(pts[1]), totalCardsWon: -1}
winners := true
for _, s := range pts[2:] {
if s == "|" {
winners = false
} else {
if winners {
ret.winners = append(ret.winners, h.Atoi(s))
} else {
ret.numbers = append(ret.numbers, h.Atoi(s))
}
}
}
for _, w := range ret.winners {
for _, n := range ret.numbers {
skip := h.IntSliceContains(ret.winsCards, w)
if n == w && !skip {
ret.winsCards = append(ret.winsCards, w)
}
if skip {
break
}
}
}
return &ret
}
func (c *Card) Value() int {
return int(math.Pow(2, float64(len(c.winsCards)-1)))
}
func (c *Card) TotalCardsWon(cm map[int]*Card) int {
if c.totalCardsWon != -1 {
return c.totalCardsWon
}
result := len(c.winsCards)
// TODO: It doesn't with cards that match the ID,
// it wins X cards increasing from the current cards ID
// where x is the number of winning numbers matched
for i := 1; i <= len(c.winsCards); i++ {
if v, ok := cm[c.id+i]; ok {
result += v.TotalCardsWon(cm)
}
}
c.totalCardsWon = result
return result
}