Day 12: JSAbacusFramework.io

Day 12.1


In [56]:
with open('inputs/input12.txt') as f_input:
    s = next(f_input).rstrip()

In [57]:
import re

def sum_numbers(s):
    p = re.compile('[-]?[\d]+')
    numbers = list(map(int, p.findall(s)))
    return sum(numbers)

In [58]:
sum_numbers(s)


Out[58]:
191164

Day 12.2

A function to transform terms of the form "[key]":"red" into a single character 'R'.


In [59]:
def transform_reds(s):
    q = re.compile('\"[\w]+\"\:\"red\"')
    return q.sub('R', s)

Track the regions to ignore: when an 'R' is found at depth d we keep this information; we ignore the span between the last $[d-1,d]$ transition (sink down) and the next $[d,d-1]$ transition (float up). Those regions will be erased.


In [60]:
def regions_to_erase(s):
    regions = []
    curr_depth = 0
    last_sink = {}
    red = None
    for i, c in enumerate(s):
        if c == '{':
            curr_depth += 1
            if red is None:
                last_sink[curr_depth] = i
        elif c == 'R':
            ignore = True
            if red is None:
                red = curr_depth
        elif c == '}':
            if red is not None:
                if curr_depth == red:
                    regions.append([last_sink[curr_depth], i])
                    red = None
            curr_depth -= 1
    return regions

Regions to erase may come out nested. If one region to erase is included inside another, we will ignore the smaller one.


In [61]:
def nest_regions(regions):
    nested = []
    for i, bounds in enumerate(regions):
        include = True
        for a in regions[i + 1:]:
            if a[0] < bounds[0]:
                include = include & False
        if include:
            nested.append(bounds)
    return nested

Gather all the functions into a main pruned_sum()


In [72]:
def pruned_sum(s):
    t = transform_reds(s)
    nested_regions = nest_regions(regions_to_erase(t))
    last_bound = 0
    pruned = ''
    for i, bounds in enumerate(nested_regions):
        pruned += t[last_bound: bounds[0]]
        last_bound = bounds[1] + 1
    pruned += t[last_bound:]
    return sum_numbers(pruned)

Test


In [74]:
def test():
    assert(pruned_sum('[1,2,3]') == 6)
    assert(pruned_sum('[1,{"c":"red","b":2},3]') == 4)
    assert(pruned_sum('{"d":"red","e":[1,2,3,4],"f":5}') == 0)
    assert(pruned_sum('[1,{"c":"red","b":2},3]') == 4)
    assert(pruned_sum('[1,"red",5]') == 6)
test()

Solution


In [76]:
pruned_sum(s)


Out[76]:
87842