aboutsummaryrefslogtreecommitdiffstats
path: root/src/21/solve.py
blob: e2b8fce48fc28e0bcb5ff514eef1a84f749681ce (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
import sys
sys.path.append("../common")
import aoc
from math import sqrt

def parse_command(l):
    s = l.split(" ")
    args = [s[0]]
    args = args + [int(v) for v in s[1:]]
    return args

data = aoc.data.split("\n")

inspaddr = int(data[0][4:])
instructs = [parse_command(l) for l in data[1:] if len(l) != 0]

register = [0 for x in range(inspaddr+1)]

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 varname(v):
    return "R"+str(v)

dismap = dict()
dismap["addr"] = lambda a, b : "%s + %s" % (varname(a), varname(b))
dismap["addi"] = lambda a, b : "%s + %d" % (varname(a), b)
dismap["mulr"] = lambda a, b : "%s * %s" % (varname(a), varname(b))
dismap["muli"] = lambda a, b : "%s * %d" % (varname(a), b)
dismap["banr"] = lambda a, b : "%s & %s" % (varname(a), varname(b))
dismap["bani"] = lambda a, b : "%s & %d" % (varname(a), b)
dismap["borr"] = lambda a, b : "%s | %s" % (varname(a), varname(b))
dismap["bori"] = lambda a, b : "%s | %d" % (varname(a), b)
dismap["setr"] = lambda a, b : "%s" % (varname(a))
dismap["seti"] = lambda a, b : "%d" % (a)
dismap["gtir"] = lambda a, b : "(%d > %s)" % (a, varname(b))
dismap["gtri"] = lambda a, b : "(%s > %d)" % (varname(a), b)
dismap["gtrr"] = lambda a, b : "(%s > %s)" % (varname(a), varname(b))
dismap["eqir"] = lambda a, b : "(%d == %s)" % (a, varname(b))
dismap["eqri"] = lambda a, b : "(%s == %d)" % (varname(a), b)
dismap["eqrr"] = lambda a, b : "(%s == %s)" % (varname(a), varname(b))

def disassemble(s, e):
    for i in range(s, e):
        ins = instructs[i]
        aoc.debug(i ,":",varname(ins[3]),"=", dismap[ins[0]](ins[1], ins[2]))
    aoc.debug()

def execute():
    global register, insptr

    while register[inspaddr] < len(instructs):
        insptr = register[inspaddr]
        ins = instructs[insptr]

        # execute command
        if len(register) <= ins[3]:
            register += [0 for x in range(ins[3] - len(register) + 1)]
        register[ins[3]] = opmap[ins[0]](ins[1], ins[2])

        # part 1
        #if insptr == 13 and register[4] == 1:
        #    aoc.debug(register)
        #    return

        # increment instruction pointer
        register[inspaddr] += 1

def solve1(args):
    r0 = 1797184 # (first opportunity for comparison r1 and r0)

    #disassemble(0, len(instructs))
    #execute()

    return r0

def solve2(args):
    r1 = 0
    candidates = list()
    while True:
        r4 = r1 | 65536 # flip 9th bit
        r1 = 3798839
        while True: # scan bytes of r4 and add them to r1 and multiply
            r5 = r4 & 255
            r1 += r5
            r1 = r1 & 16777215
            r1 *= 65899  # equals 1 00000001 01101011
            r1 = r1 & 16777215
            if r4 < 256:
                break
            r4 = int(r4/256) # bit shift 8 to the right
        if r1 not in candidates:
            candidates.append(r1)
        elif r1 == candidates[-1]:
            return candidates[-1]

aoc.run(solve1, solve2, sols=[1797184, 11011493])