mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-18 19:13:27 +02:00
103 lines
2.8 KiB
Go
103 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/alexchao26/advent-of-code-go/data-structures/slice"
|
|
|
|
"github.com/alexchao26/advent-of-code-go/util"
|
|
)
|
|
|
|
func main() {
|
|
var part int
|
|
flag.IntVar(&part, "part", 1, "part 1 or 2")
|
|
flag.Parse()
|
|
fmt.Println("Running part", part)
|
|
|
|
part1Ans, part2Ans := allergenAssessment(util.ReadFile("./input.txt"))
|
|
if part == 1 {
|
|
fmt.Println("Output:", part1Ans)
|
|
} else {
|
|
fmt.Println("Output:", part2Ans)
|
|
}
|
|
}
|
|
|
|
// leaderboard: 225/127, closest yet!
|
|
func allergenAssessment(input string) (part1Ans int, part2Ans string) {
|
|
allergensToPossibleIngredients := map[string][]string{}
|
|
ingredientCounts := map[string]int{}
|
|
|
|
for _, line := range strings.Split(input, "\n") {
|
|
parts := strings.Split(line, " (contains ")
|
|
ingredients := strings.Split(parts[0], " ")
|
|
allergens := strings.Split(strings.Trim(parts[1], ")"), ", ")
|
|
|
|
// count up the appearances for each ingredient
|
|
for _, ingred := range ingredients {
|
|
ingredientCounts[ingred]++
|
|
}
|
|
|
|
// generate all possible ingredients that could be a particular allergen
|
|
for _, a := range allergens {
|
|
// if no ingredients are there, set this as the initial list
|
|
if allergensToPossibleIngredients[a] == nil {
|
|
allergensToPossibleIngredients[a] = ingredients
|
|
} else {
|
|
// otherwise take the inner join/overlap to eliminate ingredients
|
|
allergensToPossibleIngredients[a] = slice.IntersectionStrings(allergensToPossibleIngredients[a], ingredients)
|
|
}
|
|
}
|
|
}
|
|
|
|
// iterate through the allergens to possible map and if a slice of length 1
|
|
// is found, remove that ingredient from all other value slices
|
|
// do this until every slice has only one possible ingredient
|
|
for {
|
|
allSingle := true
|
|
for allergen, possible := range allergensToPossibleIngredients {
|
|
if len(possible) != 1 {
|
|
allSingle = false
|
|
} else {
|
|
// remove this name from all lists
|
|
for otherAllergen, otherIngredients := range allergensToPossibleIngredients {
|
|
if otherAllergen != allergen {
|
|
allergensToPossibleIngredients[otherAllergen] = slice.RemoveAllStrings(otherIngredients, possible[0])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if allSingle {
|
|
break
|
|
}
|
|
}
|
|
|
|
// remove the allergens from the ingredientsCount map
|
|
for _, hashedName := range allergensToPossibleIngredients {
|
|
delete(ingredientCounts, hashedName[0])
|
|
}
|
|
|
|
// for part 1: count up the total occurrences of non-allergen ingredients
|
|
var count int
|
|
for _, ct := range ingredientCounts {
|
|
count += ct
|
|
}
|
|
|
|
// for part 2: get a list of all allergens, sort them, then in order, add the
|
|
// hashed name to a canonical dangerous list
|
|
var names []string
|
|
for k := range allergensToPossibleIngredients {
|
|
names = append(names, k)
|
|
}
|
|
sort.Strings(names)
|
|
|
|
var canonical []string
|
|
for _, n := range names {
|
|
canonical = append(canonical, allergensToPossibleIngredients[n][0])
|
|
}
|
|
|
|
return count, strings.Join(canonical, ",")
|
|
}
|