Sean McLemon | Advent of Code

Home | Czech | Blog | GitHub | Advent Of Code | Notes


2017-12-18 - Duet

(original .ipynb)
import math
from collections import defaultdict

puzzle_input_str = open("puzzle_input/day18.txt").read()

test_input_str = """set a 1
add a 2
mul a a
mod a 5
snd a
set a 0
rcv a
jgz a -1
set a 1
jgz a -2"""


def val(regs, x):
    if x.isalpha():
        return regs[x]   
    return int(x)
    
def op_snd_v1(regs, x):
    regs["frequency"] = val(regs, x)
    return 1


def op_set(regs, x, y):
    regs[x] = val(regs, y)
    return 1


def op_add(regs, x, y):
    regs[x] += val(regs, y)
    return 1


def op_mul(regs, x, y):
    regs[x] *= val(regs, y)
    return 1


def op_mod(regs, x, y):
    regs[x] %= val(regs, y)
    return 1


def op_rcv_v1(regs, x):
    if regs[x] != 0:
        return math.inf
    return 1


def op_jgz(regs, x, y):
    if val(regs, x) > 0:
        return val(regs, y)
    return 1


ops = {
    "snd": op_snd_v1,
    "set": op_set,
    "add": op_add,
    "mul": op_mul,
    "mod": op_mod,
    "rcv": op_rcv_v1,
    "jgz": op_jgz,
}


def part_one(input_str):
    instructions = [line.split(" ") for line in input_str.split("\n")]
    register_file = defaultdict(lambda: 0)
    ip = 0
    
    while ip < math.inf:        
        instr = instructions[ip]
        op = ops[instr[0]]
        ip += op(register_file, *instr[1:])

    return register_file["frequency"]


assert 4 == part_one(test_input_str)
print("part one:", part_one(puzzle_input_str))
part one: 4601
def op_snd_v2(regs, x):
    regs["out"] = val(regs, x)
    return 1


def op_rcv_v2(regs, x):
    if len(regs["in"]) > 0:
        regs[x] = regs["in"].pop(0)
        return 1
    return 0


def part_two(input_str):
    instructions = [line.split(" ") for line in input_str.split("\n")]
    register_file_0 = defaultdict(lambda: 0)
    register_file_1 = defaultdict(lambda: 0)
    ip_0 = 0
    ip_1 = 0
    
    register_file_0["in"] = []
    register_file_0["out"] = None
    register_file_1["p"] = 0
    
    register_file_1["in"] = []
    register_file_1["out"] = None
    register_file_1["p"] = 1
    
    ops["snd"] = op_snd_v2
    ops["rcv"] = op_rcv_v2
    
    program_1_sent = 0
    prev_ip_0 = None
    prev_ip_1 = None
    
    while (prev_ip_0 != ip_0) or (prev_ip_1 != ip_1):
        prev_ip_0 = ip_0
        prev_ip_1 = ip_1
                
        # run program 0
        if ip_0 < math.inf and ip_0 < len(instructions):
            instr_0 = instructions[ip_0]
            op_0 = ops[instr_0[0]]
            ip_0 += op_0(register_file_0, *instr_0[1:])
        
        # run program 1
        if ip_1 < math.inf and ip_1 < len(instructions):
            instr_1 = instructions[ip_1]
            op_1 = ops[instr_1[0]]
            ip_1 += op_1(register_file_1, *instr_1[1:])
        
        # pass values back and forward
        if register_file_0["out"]:
            register_file_1["in"].append(register_file_0["out"])
            register_file_0["out"] = None
        if register_file_1["out"]:
            register_file_0["in"].append(register_file_1["out"])
            register_file_1["out"] = None
            program_1_sent += 1

    return program_1_sent


test_input_str_2 = """snd 1
snd 2
snd p
rcv a
rcv b
rcv c
rcv d"""


assert 3 == part_two(test_input_str_2)
print("part two:", part_two(puzzle_input_str))
part two: 6858