const fs = require('fs'); const OWN_BAG = 'shiny gold'; function parseLine(line) { let [ self, others ] = line.trim().split(" bags contain "); if (self === undefined || others === undefined) return []; if (others == "no other bags.") return []; // [{a: self, b: null, count: 0}]; others = others.replace(".", "").replace(/bags?/g, "").split(","); return others.map((other) => { let [ num, ...rest ] = other.trim().split(' '); return { a: self, b: rest.join(' '), count: Number(num) }; }); } fs.readFile('input', (err, data) => { if (err) throw err; let rules = data.toString().split("\n").map( parseLine ).flat(); let bags = {}; rules.forEach((rule) => { let parent = bags[rule.a] || {spec: rule.a}; let child = bags[rule.b] || {spec: rule.b}; if (!child.hasOwnProperty('parent')) child.parent = parent; if (!parent.hasOwnProperty('children')) parent.children = []; parent.children.push(child); bags[rule.a] = parent; bags[rule.b] = child; }); let tops = Object.values(bags).filter((bag) => !bag.hasOwnProperty('parent') && bag.spec != OWN_BAG); matchBags = function(bag, parentColours) { if (bag.spec == OWN_BAG) { return parentColours; } if (!bag.children) return []; let colours = [...parentColours]; // clone colours.push(bag.spec); return bag.children.map((child) => matchBags(child, colours)).flat(); } let colours = tops.map((top) => matchBags(top, []) ).flat(); console.log( new Set(colours).size ); });