const { Glib, Maps } = require('../../lib'); const parse = (input) => Glib.fromLines(input).map((line) => { const [color, heldString] = line.split(' bags contain '); const children = []; if (heldString !== 'no other bags.') { const helds = heldString.split(', '); for (const held of helds) { const [heldDef] = held.split(' bag'); const [heldNum, ...heldColorArr] = heldDef.split(' '); const heldColor = heldColorArr.join(' '); children.push({ count: BigInt(heldNum), color: heldColor, }); } } return { color, children }; }); const parseChildren = (input) => parse(input).reduce((map, { color, children }) => { map.set(color, children); return map; }, new Map()); const parseParents = (input) => parse(input).reduce((map, { color: parentColor, children }) => { for (const { color } of children) { let parent; map.set(color, (parent = map.get(color) || new Set())); parent.add(parentColor); } return map; }, new Map()); const childrenCount = (start, graph) => { const children = graph.get(start) || []; let count = BigInt(0); for (const child of children) { count += child.count; count += childrenCount(child.color, graph) * child.count; } return count; }; module.exports = { '1': (input) => { const parents = parseParents(input); const found = new Set(parents.get('shiny gold')); let lastCount = 0; while (lastCount !== found.size) { lastCount = found.size; for (const color of found) { for (const addedColor of parents.get(color) || []) { found.add(addedColor); } } } return lastCount; }, '2': (input) => { return childrenCount('shiny gold', parseChildren(input)); }, };