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
|
import sys
sys.path.append("../common")
import aoc
def parse_log(ls):
data = list()
before = [int(v) for v in ls[0].split("[")[1].split("]")[0].split(",")]
ins = [int(v) for v in ls[1].split(" ")]
after = [int(v) for v in ls[2].split("[")[1].split("]")[0].split(",")]
return (before, ins, after)
inslog = []
data = aoc.data.split("\n")
progsec = None
for i in range(0, len(data), 4):
if data[i] == "\n":
progsec = i
break
inslog.append(parse_log(data[i:i+4]))
register = list()
opmap = dict()
opmap["addr"] = lambda a, b : register[a] + register[b]
opmap["addi"] = lambda a, b : register[a] + b
opmap["mulr"] = lambda a, b : register[a] * register[b]
opmap["muli"] = lambda a, b : register[a] * b
opmap["banr"] = lambda a, b : register[a] & register[b]
opmap["bani"] = lambda a, b : register[a] & b
opmap["borr"] = lambda a, b : register[a] | register[b]
opmap["bori"] = lambda a, b : register[a] | b
opmap["setr"] = lambda a, b : register[a]
opmap["seti"] = lambda a, b : a
opmap["gtir"] = lambda a, b : 1 * (a > register[b])
opmap["gtri"] = lambda a, b : 1 * (register[a] > b)
opmap["gtrr"] = lambda a, b : 1 * (register[a] > register[b])
opmap["eqir"] = lambda a, b : 1 * (a == register[b])
opmap["eqri"] = lambda a, b : 1 * (register[a] == b)
opmap["eqrr"] = lambda a, b : 1 * (register[a] == register[b])
def get_possible(ins):
global register
sregister = register[:]
before = ins[0]
after = ins[2]
register = before
a = ins[1][1]
b = ins[1][2]
c = ins[1][3]
ops = list(opmap.values())
possibles = list()
for i in range(len(ops)):
op = ops[i]
res = None
try:
res = op(a, b)
except:
continue
if res == after[c]:
possibles.append(i)
register = sregister
return possibles
def solve1(args):
global register
uncertain = 0
for ins in inslog:
if len(get_possible(ins)) >= 3:
uncertain += 1
return uncertain
def solve2(args):
possible = dict()
for ins in inslog:
o = ins[1][0]
if o in possible:
possible[o] = [op for op in get_possible(ins) if op in possible[o]]
else:
possible[o] = get_possible(ins)
certain = False
while not certain:
singles = [p[0] for p in possible.values() if len(p) == 1]
for p in possible:
if len(possible[p]) != 1:
possible[p] = [v for v in possible[p] if v not in singles]
certain = True
for p in possible.values():
if len(p) != 1:
certain = False
break
ntrans = dict()
for p in possible: # flatten
ntrans[p] = possible[p][0]
for i in range(progsec, len(data)): # execute program
l = data[i]
if l == "\n": continue
cmd = [int(v) for v in l.split(" ")]
while len(register)-1 < cmd[3]:
register.append(0)
register[cmd[3]] = list(opmap.values())[ntrans[cmd[0]]](cmd[1], cmd[2])
return register[0]
aoc.run(solve1, solve2, sols=[531, 649])
|