2020-12-07 01:05:49 -06:00
|
|
|
import streams, sequtils, pegs, tables, sets, algorithm, strutils
|
|
|
|
|
|
|
|
let parser = peg"""
|
|
|
|
grammar <- c ' bags contain ' (nc+ / nob) '.'
|
|
|
|
nob <- 'no other bags'
|
|
|
|
nc <- {\d} ' ' c ' bag' 's'? ', '?
|
|
|
|
c <- {\ident ' ' \ident}
|
|
|
|
"""
|
|
|
|
|
2020-12-08 06:55:34 -06:00
|
|
|
let target = "shiny gold"
|
2020-12-07 01:05:49 -06:00
|
|
|
iterator asParsed(s: Stream): (string, seq[string]) =
|
|
|
|
for l in s.lines:
|
|
|
|
if l =~ parser:
|
|
|
|
var d = matches.filterIt(it != "").reversed
|
|
|
|
let key = d.pop
|
|
|
|
yield (key, d)
|
|
|
|
|
|
|
|
proc walkUp(t: TableRef[string, HashSet[string]], tar: string): HashSet[string] =
|
|
|
|
if t.contains(tar):
|
|
|
|
let parents = t[tar]
|
|
|
|
result = parents
|
|
|
|
for p in parents:
|
|
|
|
result = result + t.walkUp(p)
|
|
|
|
|
|
|
|
proc part1*(s: Stream): int =
|
|
|
|
var t = newTable[string, HashSet[string]]()
|
|
|
|
for (key, parsed) in s.asParsed:
|
|
|
|
var parents = parsed.filterIt(not(it =~ peg"\d+"))
|
|
|
|
for p in parents:
|
|
|
|
if t.contains(p): t[p].incl(key)
|
|
|
|
else: t[p] = [key].toHashSet()
|
2020-12-08 06:55:34 -06:00
|
|
|
t.walkUp(target).len
|
2020-12-07 01:05:49 -06:00
|
|
|
|
|
|
|
proc walkDown(t: TableRef[string, TableRef[string, int]], tar: string): int =
|
|
|
|
let children = t[tar]
|
|
|
|
for (s, n) in children.pairs:
|
|
|
|
result += n + (n * t.walkDown(s))
|
|
|
|
|
|
|
|
iterator asPairChunks(s: seq[string]): (string, int) =
|
|
|
|
for i in countup(0, s.len - 1, 2): yield (s[i], s[i+1].parseInt)
|
|
|
|
|
|
|
|
proc part2*(s: Stream): int =
|
|
|
|
var t = newTable[string, TableRef[string, int]]()
|
|
|
|
for (key, parsed) in s.asParsed:
|
|
|
|
var innert = newTable[string, int]()
|
|
|
|
for (innerkey, n) in parsed.asPairChunks:
|
|
|
|
innert[innerkey] = n
|
|
|
|
t[key] = innert
|
2020-12-08 06:55:34 -06:00
|
|
|
t.walkDown target
|