Advent of Code 2023 - December 20th
Tags: advent, adventofcode, python, december
Published: 2023-12-23 09:36:23

---
title: Advent of Code 2023 - December 20th
published: true
description: My progress with the 2023 version of Advent of Code
tags: advent, adventofcode, python, december
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36qayk14ewje7rvykeg5.jpg
series: Advent of Code 2023
# published_at: 2023-12-01 17:41 +0000
---

In this series, I'll share my progress with the 2023 version of [Advent of Code](https://adventofcode.com/2023).

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

You can also follow my progress [on GitHub](https://github.com/robvanderleek/adventofcode).

## December 20th

[The puzzle of day 20](https://adventofcode.com/2023/day/20) needed a lot of code (at least for the solution I chose.) I enjoyed part one but was lost for part two (brute-force is not going to cut it.) A post on Reddit gave me a push in the right direction.

__My pitfall for this puzzle:__ I totally underestimated part two and was expecting my solution for part one would also work for part two (it did not.)

{% spoiler Solution here, do not click if you want to solve the puzzle first yourself %}

```python
#!/usr/bin/env python3

class Broadcaster:
    def __init__(self, destinations):
        self._destinations = destinations

    def process(self, name_from, pulse, stack):
        for d in self._destinations:
            stack.append('broadcaster', d, pulse) 

class Conjunction:
    def __init__(self, name, destinations):
        self._name = name
        self._destinations = destinations
        self._memory = {}

    def add_input(self, name):
        self._memory[name] = 'low'

    def process(self, name_from, pulse, stack):
        self._memory[name_from] = pulse
        if not 'low' in self._memory.values():
            for d in self._destinations:
                stack.append(self._name, d, 'low') 
            return 'low'        
        else:
            for d in self._destinations:
                stack.append(self._name, d, 'high') 
            return 'high'

class FlipFlop:
    def __init__(self, name, destinations):
        self._name = name
        self._destinations = destinations
        self._memory = 'low' 

    def add_input(self, name):
        pass

    def process(self, name_from, pulse, stack):
        if pulse == 'low':
            self._memory = 'high' if self._memory == 'low' else 'low'
            for d in self._destinations:
                stack.append(self._name, d, self._memory)

with open('input.txt') as infile:
    lines = infile.readlines()
modules = {}
for line in lines:
    parts = line.strip().split(' -> ')
    operation = parts[0]
    operands = parts[1].split(', ')
    if operation == 'broadcaster':
        modules['broadcaster'] = Broadcaster(operands)
    elif operation.startswith('&'):
        modules[operation[1:]] = Conjunction(operation[1:], operands) 
    elif operation.startswith('%'):
        modules[operation[1:]] = FlipFlop(operation[1:], operands) 

for line in lines:
    parts = line.strip().split(' -> ')
    operation = parts[0]
    operands = parts[1].split(', ')
    if operation != 'broadcaster':
        for operand in operands:
            if operand in modules:
                modules[operand].add_input(operation[1:])

class Stack:
    def __init__(self):
        self._stack = [] 
        self.count = {'low': 0, 'high': 0}

    def append(self, name_from, name_to, pulse):
        self.count[pulse] += 1
        self._stack.append((name_from, name_to, pulse))

    def next(self):
        return self._stack.pop(0)

    def is_empty(self):
        return len(self._stack) == 0

stack = Stack()
iterations = {}
for i in range(10000):
    stack.append('button', 'broadcaster', 'low')
    while not stack.is_empty():
        [name_from, name_to, pulse] = stack.next()
        if name_to in modules:
            result = modules[name_to].process(name_from, pulse, stack)
            if name_to in ['nx', 'sp', 'cc', 'jq'] and \
                name_to not in iterations and result == 'high':
                iterations[name_to] = i + 1
    if 'nx' in iterations and 'sp' in iterations and 'cc' in iterations \
        and 'jq' in iterations:  
            break

print(stack.count['low'] * stack.count['high'])
print(iterations['nx'] * iterations['sp'] * iterations['cc'] * iterations['jq'])
```

{% endspoiler %}

That's it! See you again tomorrow!