advent-20/solutions/day07.go

139 lines
3.0 KiB
Go
Raw Normal View History

2024-03-11 22:55:13 +00:00
package solutions
import (
"strconv"
"strings"
)
type Bag struct {
2024-03-12 00:35:10 +00:00
color string
contents []BagContent
// -1 if not set, 0 if it doesn't contain, 1 if it does
containsShinyGold int
// -1 if not counted yet
contentsCount int
2024-03-11 22:55:13 +00:00
}
type BagContent struct {
count int
color string
}
// Given a bag statement string, returns its contents
func parseBagStatement(bagStatement string) Bag {
bagEndIndex := strings.Index(bagStatement, " bags contain ")
bagColor := bagStatement[:bagEndIndex]
bagContentsStr := bagStatement[bagEndIndex+14:]
// if no aditional bags
if bagContentsStr[:2] == "no" {
2024-03-12 00:35:10 +00:00
return Bag{color: bagColor, contents: make([]BagContent, 0), contentsCount: -1, containsShinyGold: -1}
2024-03-11 22:55:13 +00:00
}
// parse remainder bags
bagsContained := strings.Split(bagContentsStr, ", ")
bagContents := make([]BagContent, len(bagsContained))
for idx, bag := range bagsContained {
bagCount, err := strconv.Atoi(bag[:1])
if err != nil {
panic("expected a number, got `" + bag + "`")
}
bagStrIndex := strings.Index(bag, " bag")
bagColor2 := bag[2:bagStrIndex]
bagContents[idx] = BagContent{count: bagCount, color: bagColor2}
}
2024-03-12 00:35:10 +00:00
return Bag{color: bagColor, contents: bagContents, contentsCount: -1, containsShinyGold: -1}
2024-03-11 22:55:13 +00:00
}
2024-03-12 00:35:10 +00:00
func bagContainsShinyGold(bag *Bag, bagMap map[string]*Bag) bool {
if bag.containsShinyGold == 1 {
2024-03-11 22:55:13 +00:00
return true
}
2024-03-12 00:35:10 +00:00
if bag.containsShinyGold == 0 {
return false
}
2024-03-11 22:55:13 +00:00
// recursively search
2024-03-11 23:40:19 +00:00
for _, nextBag := range bag.contents {
if nextBag.color == "shiny gold" {
2024-03-12 00:35:10 +00:00
bag.containsShinyGold = 1
2024-03-11 22:55:13 +00:00
return true
}
2024-03-12 00:35:10 +00:00
nextBagF := bagMap[nextBag.color]
if bagContainsShinyGold(nextBagF, bagMap) {
bag.containsShinyGold = 1
2024-03-11 22:55:13 +00:00
return true
}
}
2024-03-12 00:35:10 +00:00
bag.containsShinyGold = 0
2024-03-11 22:55:13 +00:00
return false
}
func Day07Part01(isTest bool) int {
input := ReadInput("07", isTest)
groups := strings.Split(input, "\n")
2024-03-12 00:04:54 +00:00
bags := make(map[string]*Bag)
2024-03-11 22:55:13 +00:00
// parse and collect the bags
2024-03-12 00:35:10 +00:00
for _, statement := range groups {
2024-03-11 22:55:13 +00:00
parsedBag := parseBagStatement(statement)
2024-03-12 00:04:54 +00:00
bags[parsedBag.color] = &parsedBag
2024-03-11 22:55:13 +00:00
}
shinyGoldContainers := 0
// process the bags
2024-03-12 00:35:10 +00:00
for _, bag := range bags {
if bagContainsShinyGold(bag, bags) {
2024-03-11 22:55:13 +00:00
shinyGoldContainers += 1
}
}
return shinyGoldContainers
}
2024-03-12 00:04:54 +00:00
func countInnerBags(bag *Bag, bagMap map[string]*Bag) int {
2024-03-11 23:20:15 +00:00
if bag.contentsCount != -1 {
return bag.contentsCount
}
innerBagsCount := 0
// recursively count bags
for _, nextBagStruct := range bag.contents {
nextBagCount := nextBagStruct.count
nextBag := bagMap[nextBagStruct.color]
2024-03-12 00:04:54 +00:00
innerBagsCount += nextBagCount + nextBagCount*countInnerBags(nextBag, bagMap)
2024-03-11 23:20:15 +00:00
}
2024-03-12 00:35:10 +00:00
bag.contentsCount = innerBagsCount
2024-03-11 23:20:15 +00:00
return innerBagsCount
}
2024-03-11 22:55:13 +00:00
func Day07Part02(isTest bool) int {
2024-03-11 23:20:15 +00:00
input := ReadInput("07", isTest)
groups := strings.Split(input, "\n")
2024-03-12 00:04:54 +00:00
bags := make(map[string]*Bag)
2024-03-11 23:20:15 +00:00
// parse and collect the bags
for _, statement := range groups {
parsedBag := parseBagStatement(statement)
2024-03-12 00:04:54 +00:00
bags[parsedBag.color] = &parsedBag
2024-03-11 23:20:15 +00:00
}
shinyGoldBag := bags["shiny gold"]
2024-03-12 00:04:54 +00:00
return countInnerBags(shinyGoldBag, bags)
2024-03-11 22:55:13 +00:00
}