DEV Community

Cover image for Advent of Code 2023 - December 19th
Rob van der Leek
Rob van der Leek

Posted on

Advent of Code 2023 - December 19th

In this series, I'll share my progress with the 2023 version of Advent of Code.

Check the first post for a short intro to this series.

You can also follow my progress on GitHub.

December 19th

The puzzle of day 19 is pretty fun, although I'm still working on the second part.
UPDATE: Part two is now also completed.

My pitfall for this puzzle: Not really so far, I hope graph walking will be the answer for part two, but that's still left to do.
UPDATE: Graph walking did the trick. I actually liked this puzzle a lot.

Solution here, do not click if you want to solve the puzzle first yourself
#!/usr/bin/env python3
import json

with open('input.txt') as infile:
    lines = infile.readlines()
    workflows = {} 
    parts = []
    in_workflows = True
    for line in lines:
        if line.strip() == '':
            in_workflows = False
            continue
        if in_workflows:
            workflow = []
            val = line.strip()[:-1].split('{')
            workflows[val[0]] = val[1]
        else:
            part = {}
            for c in line.strip()[1:-1].split(','):
                val = c.split('=') 
                part[val[0]] = int(val[1])
            parts.append(part)

def parse_exp(exp):
    ch = exp[0]
    operator = exp[1]
    val = int(exp[2:])
    return [ch, operator, val]

def revert(ch, operator, val):
    return [ch, '>', val - 1] if operator == '<' else [ch, '<', val + 1]

def execute(workflow, part):
    rules = workflow.split(',')
    for rule in rules[:-1]:
        split = rule.split(':')
        exp = split[0]
        target = split[1]
        [ch, operator, val] = parse_exp(exp)
        if operator == '<':
            if part[ch] < val:
                return target 
        else:
            if part[ch] > val:
                return target 
    return rules[-1]

def process(part):
    workflow = workflows['in']
    while True:
        result = execute(workflow, part)
        if result in ['A', 'R']:
            return result
        else: 
            workflow = workflows[result] 

result = 0
for p in parts:
    if process(p) == 'A':
        result += p['x'] + p['m'] + p['a'] + p['s']
print(result)

nodes = edges = []
for k, v in workflows.items():
    if not k in nodes:
        nodes.append(k)
    rules = v.split(',')
    exps = []
    for rule in rules[:-1]: 
        split = rule.split(':')
        exp = split[0]
        target = split[1]
        [ch, op, val] = parse_exp(exp)
        edges.append((k, target, exps + [[ch, op, val]]))
        exps.append(revert(ch, op, val))
    edges.append((k, rules[-1], exps))

def walk(node, end, path, paths, nodes):
    if node == end:
        paths.append(path)
        return paths
    else:
        for e in edges:
            if e[0] == node:
                walk(e[1], end, path + e[2], paths, nodes + [node])
    return paths

total = 0
for p in walk('in', 'A', [], [], []):
    b = {'x': [1, 4000], 'm': [1, 4000], 'a': [1, 4000], 's': [1, 4000]}
    for pb in p:
        ch_bounds = b[pb[0]]
        if pb[1] == '<' and ch_bounds[1] > pb[2] - 1:
            ch_bounds[1] = pb[2] - 1
        elif ch_bounds[0] < pb[2] + 1:
            ch_bounds[0] = pb[2] + 1
    total += (b['x'][1] - b['x'][0] + 1) * (b['m'][1] - b['m'][0] + 1) * \
             (b['a'][1] - b['a'][0] + 1) * (b['s'][1] - b['s'][0] + 1)
print(total)
Enter fullscreen mode Exit fullscreen mode

That's it! See you again tomorrow!

Top comments (0)