let input = Deno.readTextFileSync("input.dat").split("\n")
input.pop() // remove empty final value

const rules = {}

for (let line of input) {
  const contents = []
  const [outerColor, contentsStr] = line.split(" bags contain ")
  const contentsArr = contentsStr.split(", ").filter(s => s !== "no other bags.")

  for (let content of contentsArr) {
    const [, count, color] = /^(\d) (.*) bag/.exec(content)
    contents.push({color, count: Number(count)})
  }

  rules[outerColor] = contents
}

function partOne(rules, target) {
  const goodColors = []

  for (let [outerColor, contents] of Object.entries(rules)) {
    while (contents.length) {
      if (contents.some(bag => bag.color === target)) {
        goodColors.push(outerColor)
        break
      }
      let newContents = []
      for (let { color } of contents) {
        newContents = newContents.concat(rules[color])
      }
      contents = newContents
    }
  }

  return [...new Set(goodColors)].length
}

function partTwo(rules, target) {
  let total = 0
  let contents = rules[target]
  while (contents.length) {
    let newContents = []
    for (let { color, count } of contents) {
      total += count
      let newBags = rules[color].map(newBag => ({count: newBag.count * count, color: newBag.color}))
      newContents = newContents.concat(newBags)
    }
    contents = newContents
  }
  return total
}

console.log("part one:", partOne(rules, "shiny gold"))
console.log("part two:", partTwo(rules, "shiny gold"))