package main import ( "flag" "fmt" "math" "os" "regexp" "strconv" "strings" ) var ( inputFile = flag.String("input", "input.txt", "input filename") subsetRegex = regexp.MustCompile(`(?mi)(\d+)+\s(\w+)([,;]?)`) idRegex = regexp.MustCompile(`(?mi)Game\s(\d+):`) ) const ( BlueCube = "blue" GreenCube = "green" RedCube = "red" MaxRed = 12 MaxGreen = 13 MaxBlue = 14 ) func main() { flag.Parse() input, err := os.ReadFile(*inputFile) if err != nil { panic(err) } var sum int var powSum float64 for _, line := range strings.Split(string(input), "\n") { if strings.TrimSpace(line) == "" { continue } // find id idMatch := idRegex.FindAllStringSubmatch(line, -1) id, err := strconv.Atoi(idMatch[0][1]) if err != nil { panic(err) } // find sets of digit + color + separator (e.g. "3 blue,") subsets := subsetRegex.FindAllStringSubmatch(line, -1) var red, green, blue float64 var minRed, minGreen, minBlue float64 possible := true for _, subset := range subsets { cubeAmount, err := strconv.ParseFloat(subset[1], 64) if err != nil { panic(err) } // add cube amount to set switch strings.ToLower(subset[2]) { case BlueCube: blue += cubeAmount case GreenCube: green += cubeAmount case RedCube: red += cubeAmount } // end of set reached if subset[3] == "" || subset[3] == ";" { if red > MaxRed || green > MaxGreen || blue > MaxBlue { possible = false } minBlue = math.Max(minBlue, blue) minRed = math.Max(minRed, red) minGreen = math.Max(minGreen, green) red = 0 blue = 0 green = 0 } } // end of game reached powSum += minRed * minGreen * minBlue if possible { fmt.Printf("%d possible\n", id) sum += id } } fmt.Printf("Sum of IDs: %d\n", sum) fmt.Printf("Sum of the power of sets: %d", int(powSum)) }