import std; void main() { readText("input").calculateNumberOfRequiredBags("shiny gold").writeln; } auto calculateNumberOfRequiredBags(string rules, string bag) { return rules.parseRules.calculateNumberOfRequiredBags(bag) - 1; } int calculateNumberOfRequiredBags(Tuple!(int, string)[][string] containmentMap, string bag) { return 1 + containmentMap[bag].map!(containedBag => containedBag[0] * containmentMap.calculateNumberOfRequiredBags(containedBag[1])).sum; } auto parseRules(string rules) { Tuple!(int, string)[][string] containmentMap; rules.splitter("\n").filter!(not!empty) .each!((rule) { auto spec = rule.split(" bags contain "); containmentMap[spec[0]] = spec[1].splitter(", ").filter!(it => it != "no other bags.") .map!((bagSpec) { auto match = bagSpec.matchFirst(r"(\d+) (.+) (bag|bags)\.*"); return tuple(match[1].to!int, match[2]); }) .array; }); return containmentMap; } unittest { auto input = `light red bags contain 1 bright white bag, 2 muted yellow bags. dark orange bags contain 3 bright white bags, 4 muted yellow bags. bright white bags contain 1 shiny gold bag. muted yellow bags contain 2 shiny gold bags, 9 faded blue bags. shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags. dark olive bags contain 3 faded blue bags, 4 dotted black bags. vibrant plum bags contain 5 faded blue bags, 6 dotted black bags. faded blue bags contain no other bags. dotted black bags contain no other bags.`; assert(input.calculateNumberOfRequiredBags("shiny gold") == 32); }