Advent-of-Code-2023/day4/dayFour.go

173 lines
4.3 KiB
Go

package day4
import (
"fmt"
"os"
"strconv"
"strings"
)
func Run() int {
fmt.Println("in day 4")
cards := ReadAllCards()
fmt.Printf("> got cards %+v\n", cards)
// result := 0
// for _, card := range cards {
// // fmt.Printf("> checking card %+v with points %d", card, card.GetPoints())
// result += card.GetPoints()
// }
result := ActuallWinCounting(cards)
return result
}
// starting from card #1 count how many winning points it has
// then add copies to map of 'amount of cards i have'
// multiplied to amount of current card i have, ok i guess
func ActuallWinCounting(cards []Card) int {
cardAmounts := make(map[int]int)
// i had off-by-one error, with card 204 not being updated from 196
maxCard := len(cards)
fmt.Printf("> counting winning, total cards are %d\ncards are %+v\n\n", maxCard, cards)
for _, card := range cards {
fmt.Printf("> checking card %d\n", card.Title)
winningNums := card.GetWinNums()
curCardAmount, found := cardAmounts[card.Title]
if !found {
curCardAmount = 1
cardAmounts[card.Title] = curCardAmount
}
fmt.Printf(">> from curCard %d winning points are %d. And it's amount is %d\n", card.Title, winningNums, curCardAmount)
for i := 1; i <= winningNums; i++ {
childCardNum := card.Title + i
if childCardNum > maxCard {
fmt.Printf(">>>> should skip increasing child card %d from curCard %d\n", childCardNum, card.Title)
break
}
curAmount, found := cardAmounts[childCardNum]
if !found {
cardAmounts[childCardNum] = 1 + curCardAmount
} else {
cardAmounts[childCardNum] += curCardAmount
}
fmt.Printf(">> increasing child card %d from %d to %d by curCard %d\n", childCardNum, curAmount, cardAmounts[childCardNum], card.Title)
}
}
var result int = 0
for _, amount := range cardAmounts {
result += amount
}
fmt.Printf("> got card amounts: %+v\n", cardAmounts)
return result
}
type Card struct {
Title int
WinningNums []int
OwnNums []int
}
func ReadAllCards() []Card {
filename := "day4/input"
bytes, err := os.ReadFile(filename)
if err != nil {
panic(fmt.Sprintf("can't read file %s", filename))
}
text := string(bytes)
lines := strings.Split(text, "\n")
result := make([]Card, 0, len(lines))
for _, line := range lines {
if line == "" {
continue
}
result = append(result, ReadCard(line))
}
return result
}
// read line like 'Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53'
func ReadCard(line string) Card {
fmt.Printf(">> reading line %s\n", line)
result := Card{}
extractingTitle := strings.Split(line, ":")
title := extractingTitle[0]
numberPart := extractingTitle[1]
titleNumStr := strings.Fields(title)[1]
titleNum, err := strconv.Atoi(titleNumStr)
if err != nil {
panic(fmt.Sprintf("error extracting card title: %s, %s", line, titleNumStr))
}
result.Title = titleNum
extractingNumbers := strings.Split(numberPart, "|")
for _, winningNumStr := range strings.Split( extractingNumbers[0], " " ) {
winningNumStr = strings.TrimSpace(winningNumStr)
if winningNumStr == "" {
continue
}
winningNum, err := strconv.Atoi(winningNumStr)
if err != nil {
panic(fmt.Sprintf("error extracting winning card num: %s from '%s'", line, winningNumStr))
}
result.WinningNums = append(result.WinningNums, winningNum)
}
for _, ownNumStr := range strings.Split( extractingNumbers[1], " " ) {
ownNumStr = strings.TrimSpace(ownNumStr)
if ownNumStr == "" {
continue
}
ownNum, err := strconv.Atoi(ownNumStr)
if err != nil {
panic(fmt.Sprintf("error extracting own card num: %s, %s", line, ownNumStr))
}
result.OwnNums = append(result.OwnNums, ownNum)
}
fmt.Printf(">>> returning %+v\n", result)
return result
}
func (c *Card)GetWinNums() int {
winningSet := make(map[int]any)
for _, winNum := range c.WinningNums {
winningSet[winNum] = struct{}{}
}
result := 0
for _, ownNum := range c.OwnNums {
_, isWinning := winningSet[ownNum]
if isWinning {
result += 1
}
}
return result
}
func (c *Card)GetPoints() int {
winningSet := make(map[int]any)
for _, winNum := range c.WinningNums {
winningSet[winNum] = struct{}{}
}
result := 0
hasMatch := false
for _, ownNum := range c.OwnNums {
_, isWinning := winningSet[ownNum]
if isWinning {
if !hasMatch {
result = 1
hasMatch = true
} else {
result *= 2
}
}
}
return result
}