135 lines
2.3 KiB
Go
135 lines
2.3 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
func noErr(err error) {
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
// parsing
|
||
|
input, err := os.ReadFile("input.txt")
|
||
|
noErr(err)
|
||
|
lines := strings.Split(string(input), "\n")
|
||
|
cards := make([]Card, len(lines))
|
||
|
cardCounts := map[int]int{}
|
||
|
for idx, l := range lines {
|
||
|
card, err := LineToCard(l)
|
||
|
noErr(err)
|
||
|
cards[idx] = card
|
||
|
cardCounts[card.Id] = 1
|
||
|
}
|
||
|
|
||
|
// part 1
|
||
|
s := 0
|
||
|
for _, c := range cards {
|
||
|
s += c.Points()
|
||
|
}
|
||
|
println("Part 1:", s)
|
||
|
|
||
|
// part 2
|
||
|
t := 0
|
||
|
for _, c := range cards {
|
||
|
t += cardCounts[c.Id]
|
||
|
for n := 1; n <= c.Wins(); n++ {
|
||
|
_, exists := cardCounts[c.Id+n]
|
||
|
if exists {
|
||
|
cardCounts[c.Id+n] += cardCounts[c.Id]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
println("Part 2:", t)
|
||
|
}
|
||
|
|
||
|
type Card struct {
|
||
|
Id int
|
||
|
WinningNs []int
|
||
|
MyNs []int
|
||
|
}
|
||
|
|
||
|
func (card Card) Wins() int {
|
||
|
c := 0
|
||
|
for _, w := range card.WinningNs {
|
||
|
for _, n := range card.MyNs {
|
||
|
if w == n {
|
||
|
c++
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
func (card Card) Points() int {
|
||
|
// math.Pow with into to float conversion feels wrong
|
||
|
p := 1
|
||
|
for _, w := range card.WinningNs {
|
||
|
for _, n := range card.MyNs {
|
||
|
if w == n {
|
||
|
p *= 2
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if p == 1 {
|
||
|
return 0
|
||
|
}
|
||
|
return p / 2
|
||
|
}
|
||
|
|
||
|
var NoCutErr = errors.New("no cut found")
|
||
|
|
||
|
func LineToCard(line string) (Card, error) {
|
||
|
cardIdStr, nStr, f := strings.Cut(line, ":")
|
||
|
if !f {
|
||
|
return Card{}, fmt.Errorf("cut ':': %w", NoCutErr)
|
||
|
}
|
||
|
_, idStr, f := strings.Cut(cardIdStr, " ")
|
||
|
if !f {
|
||
|
return Card{}, fmt.Errorf("cut ' ': %w", NoCutErr)
|
||
|
}
|
||
|
id, err := strconv.Atoi(strings.TrimSpace(idStr))
|
||
|
if err != nil {
|
||
|
return Card{}, fmt.Errorf("card id: %w", err)
|
||
|
}
|
||
|
cardNStrs, myNStrs, f := strings.Cut(nStr, "|")
|
||
|
if !f {
|
||
|
return Card{}, fmt.Errorf("cut '|': %w", NoCutErr)
|
||
|
}
|
||
|
cardNs, err := strToNumbers(cardNStrs)
|
||
|
if err != nil {
|
||
|
return Card{}, fmt.Errorf("card ns: %w", err)
|
||
|
}
|
||
|
myNs, err := strToNumbers(myNStrs)
|
||
|
if err != nil {
|
||
|
return Card{}, fmt.Errorf("my ns: %w", err)
|
||
|
}
|
||
|
return Card{
|
||
|
Id: id,
|
||
|
WinningNs: cardNs,
|
||
|
MyNs: myNs,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func strToNumbers(str string) ([]int, error) {
|
||
|
nStrs := strings.Split(str, " ")
|
||
|
ns := make([]int, 0)
|
||
|
for _, nStr := range nStrs {
|
||
|
if nStr == "" {
|
||
|
continue
|
||
|
}
|
||
|
n, err := strconv.Atoi(strings.TrimSpace(nStr))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
ns = append(ns, n)
|
||
|
}
|
||
|
return ns, nil
|
||
|
}
|