about summary refs log tree commit diff
path: root/scratch/advent-of-code-2019/day_5.py
blob: 3d82846e6126ec162f1502122f0a5d5fb043e5fc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
x = [
    3, 225, 1, 225, 6, 6, 1100, 1, 238, 225, 104, 0, 1102, 31, 68, 225, 1001,
    13, 87, 224, 1001, 224, -118, 224, 4, 224, 102, 8, 223, 223, 1001, 224, 7,
    224, 1, 223, 224, 223, 1, 174, 110, 224, 1001, 224, -46, 224, 4, 224, 102,
    8, 223, 223, 101, 2, 224, 224, 1, 223, 224, 223, 1101, 13, 60, 224, 101,
    -73, 224, 224, 4, 224, 102, 8, 223, 223, 101, 6, 224, 224, 1, 224, 223,
    223, 1101, 87, 72, 225, 101, 47, 84, 224, 101, -119, 224, 224, 4, 224,
    1002, 223, 8, 223, 1001, 224, 6, 224, 1, 223, 224, 223, 1101, 76, 31, 225,
    1102, 60, 43, 225, 1102, 45, 31, 225, 1102, 63, 9, 225, 2, 170, 122, 224,
    1001, 224, -486, 224, 4, 224, 102, 8, 223, 223, 101, 2, 224, 224, 1, 223,
    224, 223, 1102, 29, 17, 224, 101, -493, 224, 224, 4, 224, 102, 8, 223, 223,
    101, 1, 224, 224, 1, 223, 224, 223, 1102, 52, 54, 225, 1102, 27, 15, 225,
    102, 26, 113, 224, 1001, 224, -1560, 224, 4, 224, 102, 8, 223, 223, 101, 7,
    224, 224, 1, 223, 224, 223, 1002, 117, 81, 224, 101, -3645, 224, 224, 4,
    224, 1002, 223, 8, 223, 101, 6, 224, 224, 1, 223, 224, 223, 4, 223, 99, 0,
    0, 0, 677, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1105, 0, 99999, 1105, 227, 247,
    1105, 1, 99999, 1005, 227, 99999, 1005, 0, 256, 1105, 1, 99999, 1106, 227,
    99999, 1106, 0, 265, 1105, 1, 99999, 1006, 0, 99999, 1006, 227, 274, 1105,
    1, 99999, 1105, 1, 280, 1105, 1, 99999, 1, 225, 225, 225, 1101, 294, 0, 0,
    105, 1, 0, 1105, 1, 99999, 1106, 0, 300, 1105, 1, 99999, 1, 225, 225, 225,
    1101, 314, 0, 0, 106, 0, 0, 1105, 1, 99999, 8, 226, 677, 224, 102, 2, 223,
    223, 1005, 224, 329, 1001, 223, 1, 223, 1108, 677, 226, 224, 102, 2, 223,
    223, 1006, 224, 344, 101, 1, 223, 223, 108, 677, 226, 224, 102, 2, 223,
    223, 1006, 224, 359, 101, 1, 223, 223, 7, 677, 226, 224, 102, 2, 223, 223,
    1005, 224, 374, 101, 1, 223, 223, 1007, 226, 677, 224, 102, 2, 223, 223,
    1005, 224, 389, 101, 1, 223, 223, 8, 677, 677, 224, 102, 2, 223, 223, 1006,
    224, 404, 1001, 223, 1, 223, 1007, 677, 677, 224, 1002, 223, 2, 223, 1006,
    224, 419, 101, 1, 223, 223, 1108, 677, 677, 224, 1002, 223, 2, 223, 1005,
    224, 434, 1001, 223, 1, 223, 1107, 226, 677, 224, 102, 2, 223, 223, 1005,
    224, 449, 101, 1, 223, 223, 107, 226, 226, 224, 102, 2, 223, 223, 1006,
    224, 464, 101, 1, 223, 223, 1108, 226, 677, 224, 1002, 223, 2, 223, 1005,
    224, 479, 1001, 223, 1, 223, 7, 677, 677, 224, 102, 2, 223, 223, 1006, 224,
    494, 1001, 223, 1, 223, 1107, 677, 226, 224, 102, 2, 223, 223, 1005, 224,
    509, 101, 1, 223, 223, 107, 677, 677, 224, 1002, 223, 2, 223, 1006, 224,
    524, 101, 1, 223, 223, 1008, 677, 677, 224, 1002, 223, 2, 223, 1006, 224,
    539, 101, 1, 223, 223, 7, 226, 677, 224, 1002, 223, 2, 223, 1005, 224, 554,
    101, 1, 223, 223, 108, 226, 226, 224, 1002, 223, 2, 223, 1006, 224, 569,
    101, 1, 223, 223, 1008, 226, 677, 224, 102, 2, 223, 223, 1005, 224, 584,
    101, 1, 223, 223, 8, 677, 226, 224, 1002, 223, 2, 223, 1005, 224, 599, 101,
    1, 223, 223, 1007, 226, 226, 224, 1002, 223, 2, 223, 1005, 224, 614, 101,
    1, 223, 223, 1107, 226, 226, 224, 1002, 223, 2, 223, 1006, 224, 629, 101,
    1, 223, 223, 107, 677, 226, 224, 1002, 223, 2, 223, 1005, 224, 644, 1001,
    223, 1, 223, 1008, 226, 226, 224, 1002, 223, 2, 223, 1006, 224, 659, 101,
    1, 223, 223, 108, 677, 677, 224, 1002, 223, 2, 223, 1005, 224, 674, 1001,
    223, 1, 223, 4, 223, 99, 226
]

# Interpretter spec:
# Op-code width: 2
# ABCDE
# A:  Mode of 3rd parameter
# B:  Mode of 2rd parameter
# C:  Mode of 1st parameter
# DE: 2-digit op-code
#
# Not every op-code has the same arity.
#
# Parameter modes:
# - positional: index of memory. 0
# - immediate: raw value. 1
# Assert that you never attempt to write to an "immediate value"

# Parameter modes
POS = '0'  # positional parameter mode
VAL = '1'  # immediate parameter mode


# Pasted from day-2.py
# interpretter :: Int -> [Int] -> [Int] -> IO ()
def interpret(i, x, argv=[], outs=[]):
    """Values in `argv` will be applied to any `input` fields."""
    # The widest op-code we'll see is 3 + 2 = 5 for either addition or
    # multiplication since each of those is a 3-arity function with a two-digit
    # op-code.
    instruction = '{:05d}'.format(x[i])
    op = instruction[-2:]

    if op == '01':
        a, b, out = x[i + 1], x[i + 2], x[i + 3]
        mode_a, mode_b, mode_out = instruction[2], instruction[1], instruction[
            0]
        a = a if mode_a == VAL else x[a]
        b = b if mode_b == VAL else x[b]
        assert mode_out == POS
        x[out] = a + b
        return interpret(i + 4, x, argv=argv, outs=outs)
    elif op == '02':
        a, b, out = x[i + 1], x[i + 2], x[i + 3]
        mode_a, mode_b, mode_out = instruction[2], instruction[1], instruction[
            0]
        a = a if mode_a == VAL else x[a]
        b = b if mode_b == VAL else x[b]
        assert mode_out == POS
        x[out] = a * b
        return interpret(i + 4, x, argv=argv, outs=outs)
    # input
    elif op == '03':
        a = x[i + 1]
        mode_a = instruction[2]
        assert mode_a == POS
        # What's the pythonic way to defensively get this value?
        if len(argv) and argv[0] is not None:
            x[a] = argv[0]
            return interpret(i + 2, x, argv=argv[1:], outs=outs)
        elif len(outs) and outs[-1] is not None:
            x[a] = outs[-1]
            return interpret(i + 2, x, argv=argv, outs=outs)
        else:
            # Here we want to block until the user applies input. This could be
            # done easily with message passing for something similar.
            x[a] = int(input('Enter: '))
            return interpret(i + 2, x, argv=argv)
    # output
    elif op == '04':
        a = x[i + 1]
        mode_a = instruction[2]
        a = a if mode_a == VAL else x[a]
        outs.append(a)
        return interpret(i + 2, x, argv=argv, outs=outs)
    # jump-if-true
    elif op == '05':
        a, b = x[i + 1], x[i + 2]
        mode_a, mode_b = instruction[2], instruction[1]
        a = a if mode_a == VAL else x[a]
        b = b if mode_b == VAL else x[b]
        if a != 0:
            return interpret(b, x, argv=argv, outs=outs)
        else:
            return interpret(i + 3, x, argv=argv, outs=outs)
    # jump-if-false
    elif op == '06':
        a, b = x[i + 1], x[i + 2]
        mode_a, mode_b = instruction[2], instruction[1]
        a = a if mode_a == VAL else x[a]
        b = b if mode_b == VAL else x[b]
        if a == 0:
            return interpret(b, x, argv=argv, outs=outs)
        else:
            return interpret(i + 3, x, argv=argv, outs=outs)
        pass
    # less than
    elif op == '07':
        a, b, out = x[i + 1], x[i + 2], x[i + 3]
        mode_a, mode_b, mode_out = instruction[2], instruction[1], instruction[
            0]
        a = a if mode_a == VAL else x[a]
        b = b if mode_b == VAL else x[b]
        assert mode_out == POS
        if a < b:
            x[out] = 1
        else:
            x[out] = 0
        return interpret(i + 4, x, argv=argv, outs=outs)
    # equals
    elif op == '08':
        a, b, out = x[i + 1], x[i + 2], x[i + 3]
        mode_a, mode_b, mode_out = instruction[2], instruction[1], instruction[
            0]
        a = a if mode_a == VAL else x[a]
        b = b if mode_b == VAL else x[b]
        assert mode_out == POS
        if a == b:
            x[out] = 1
        else:
            x[out] = 0
        return interpret(i + 4, x, argv=argv, outs=outs)
    elif op == '99':
        return x[0]
    else:
        raise Exception('Unsupported opcode: {}.'.format(op))