Add day 4 part 2
parent
ab92cf620a
commit
8900459fc6
111
day4/main.go
111
day4/main.go
|
@ -6,31 +6,48 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Card struct {
|
||||
id int
|
||||
winningNumbers []int
|
||||
ourNumbers []int
|
||||
}
|
||||
|
||||
func (card Card) Score() int {
|
||||
score := 0
|
||||
func (card Card) NumMatchingNumbers() int {
|
||||
matchingNumbers := 0
|
||||
|
||||
winningNumbers := makeSet(card.winningNumbers)
|
||||
for _, ourNumber := range card.ourNumbers {
|
||||
if _, ok := winningNumbers[ourNumber]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if score == 0 {
|
||||
score = 1
|
||||
} else {
|
||||
score *= 2
|
||||
if _, ok := winningNumbers[ourNumber]; ok {
|
||||
matchingNumbers++
|
||||
}
|
||||
}
|
||||
|
||||
return score
|
||||
return matchingNumbers
|
||||
}
|
||||
|
||||
func (card Card) Score() int {
|
||||
numMatchingNumbers := card.NumMatchingNumbers()
|
||||
if numMatchingNumbers == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return pow2(numMatchingNumbers)
|
||||
}
|
||||
|
||||
func (card Card) WinsCardsWithIDs() []int {
|
||||
numMatchingNumbers := card.NumMatchingNumbers()
|
||||
|
||||
wonCards := make([]int, numMatchingNumbers)
|
||||
for i := 0; i < numMatchingNumbers; i++ {
|
||||
wonCards[i] = card.id + i + 1
|
||||
}
|
||||
|
||||
return wonCards
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -60,6 +77,7 @@ func main() {
|
|||
}
|
||||
|
||||
fmt.Printf("Part 1: %d\n", part1(cards))
|
||||
fmt.Printf("Part 2: %d\n", part2(cards))
|
||||
}
|
||||
|
||||
func part1(cards []Card) int {
|
||||
|
@ -71,28 +89,76 @@ func part1(cards []Card) int {
|
|||
return score
|
||||
}
|
||||
|
||||
func part2(cards []Card) int {
|
||||
if len(cards) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
cardsByID := map[int]Card{}
|
||||
for _, card := range cards {
|
||||
cardsByID[card.id] = card
|
||||
}
|
||||
|
||||
// This solution is a bit naive; I didn't get particularly clever with
|
||||
// the number of cards we had and treated it like a tree problem (I could
|
||||
// have just made this faster by doing
|
||||
// visitedCardIds[wonCard] += visitedCardIds[card.id]
|
||||
// which would have been equivalent, and faster, but meh, I like this
|
||||
// solution even if it's slow)
|
||||
visitedCardIDs := map[int]int{}
|
||||
cardsInPlay := slices.Clone(cards)
|
||||
|
||||
for len(cardsInPlay) > 0 {
|
||||
card := cardsInPlay[0]
|
||||
cardsInPlay = cardsInPlay[1:]
|
||||
|
||||
visitedCardIDs[card.id]++
|
||||
|
||||
wonCardIDs := card.WinsCardsWithIDs()
|
||||
for _, wonCardID := range wonCardIDs {
|
||||
cardsInPlay = append(cardsInPlay, cardsByID[wonCardID])
|
||||
}
|
||||
}
|
||||
|
||||
totalCards := 0
|
||||
for _, numVisited := range visitedCardIDs {
|
||||
totalCards += numVisited
|
||||
}
|
||||
|
||||
return totalCards
|
||||
}
|
||||
|
||||
func parseCards(inputLines []string) ([]Card, error) {
|
||||
return tryParse(inputLines, parseCard)
|
||||
}
|
||||
|
||||
func parseCard(inputLine string) (Card, error) {
|
||||
pattern := regexp.MustCompile(`^Card\s+\d+: ((?:\s*\d+\s*?)+) \| ((?:\s*\d+\s*)+)$`)
|
||||
pattern := regexp.MustCompile(`^Card\s+(\d+): ((?:\s*\d+\s*?)+) \| ((?:\s*\d+\s*)+)$`)
|
||||
matches := pattern.FindStringSubmatch(inputLine)
|
||||
if matches == nil {
|
||||
return Card{}, errors.New("did not match line pattern")
|
||||
}
|
||||
|
||||
winningNumbers, err := parseCardNumbers(matches[1])
|
||||
id, err := strconv.Atoi(matches[1])
|
||||
if err != nil {
|
||||
return Card{}, fmt.Errorf("parse id: %w", err)
|
||||
}
|
||||
|
||||
winningNumbers, err := parseCardNumbers(matches[2])
|
||||
if err != nil {
|
||||
return Card{}, fmt.Errorf("parse winning numbers: %w", err)
|
||||
}
|
||||
|
||||
ourNumbers, err := parseCardNumbers(matches[2])
|
||||
ourNumbers, err := parseCardNumbers(matches[3])
|
||||
if err != nil {
|
||||
return Card{}, fmt.Errorf("parse winning numbers: %w", err)
|
||||
return Card{}, fmt.Errorf("parse our numbers: %w", err)
|
||||
}
|
||||
|
||||
return Card{winningNumbers: winningNumbers, ourNumbers: ourNumbers}, nil
|
||||
return Card{
|
||||
id: id,
|
||||
winningNumbers: winningNumbers,
|
||||
ourNumbers: ourNumbers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func normalizeSeparatingSpaces(s string) string {
|
||||
|
@ -131,3 +197,16 @@ func makeSet[T comparable, S ~[]T](items S) map[T]struct{} {
|
|||
|
||||
return set
|
||||
}
|
||||
|
||||
func pow2(exp int) int {
|
||||
if exp == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
res := 1
|
||||
for i := 1; i < exp; i++ {
|
||||
res *= 2
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue