diff options
| author | Louis Burda <quent.burda@gmail.com> | 2023-04-07 17:18:18 -0400 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2023-04-07 17:19:39 -0400 |
| commit | 87ab487d59fa85dbe2afa55cc841b02805ae42ca (patch) | |
| tree | cd90ab715e1b5b5803674045dbafd6d51d27ac90 /src/19 | |
| parent | 1bcc82c5bfbde87edd03c01ffdf9ee5934681592 (diff) | |
| download | aoc2018-python-87ab487d59fa85dbe2afa55cc841b02805ae42ca.tar.gz aoc2018-python-87ab487d59fa85dbe2afa55cc841b02805ae42ca.zip | |
Reorder days into src
Diffstat (limited to 'src/19')
| -rw-r--r-- | src/19/input | 37 | ||||
| -rw-r--r-- | src/19/part1 | 92 | ||||
| -rw-r--r-- | src/19/part2 | 58 | ||||
| -rw-r--r-- | src/19/solve.py | 109 | ||||
| -rw-r--r-- | src/19/test1 | 8 |
5 files changed, 304 insertions, 0 deletions
diff --git a/src/19/input b/src/19/input new file mode 100644 index 0000000..0392b90 --- /dev/null +++ b/src/19/input @@ -0,0 +1,37 @@ +#ip 4
+addi 4 16 4
+seti 1 5 1
+seti 1 2 2
+mulr 1 2 3
+eqrr 3 5 3
+addr 3 4 4
+addi 4 1 4
+addr 1 0 0
+addi 2 1 2
+gtrr 2 5 3
+addr 4 3 4
+seti 2 7 4
+addi 1 1 1
+gtrr 1 5 3
+addr 3 4 4
+seti 1 9 4
+mulr 4 4 4
+addi 5 2 5
+mulr 5 5 5
+mulr 4 5 5
+muli 5 11 5
+addi 3 1 3
+mulr 3 4 3
+addi 3 18 3
+addr 5 3 5
+addr 4 0 4
+seti 0 3 4
+setr 4 2 3
+mulr 3 4 3
+addr 4 3 3
+mulr 4 3 3
+muli 3 14 3
+mulr 3 4 3
+addr 5 3 5
+seti 0 4 0
+seti 0 5 4
diff --git a/src/19/part1 b/src/19/part1 new file mode 100644 index 0000000..1a9c60b --- /dev/null +++ b/src/19/part1 @@ -0,0 +1,92 @@ +--- Day 19: Go With The Flow --- + +With the Elves well on their way constructing the North Pole base, you turn your attention back to +understanding the inner workings of programming the device. + +You can't help but notice that the device's opcodes don't contain any [1m[97mflow control[0m like jump +instructions. The device's manual goes on to explain: + +"In programs where flow control is required, the instruction pointer can be [1m[97mbound to a register[0m so +that it can be manipulated directly. This way, setr/seti can function as absolute jumps, addr/addi +can function as relative jumps, and other opcodes can cause truly fascinating effects." + +This mechanism is achieved through a declaration like #ip 1, which would modify register 1 so that +accesses to it let the program indirectly access the instruction pointer itself. To compensate for +this kind of binding, there are now [1m[97msix[0m registers (numbered 0 through 5); the five not bound to the +instruction pointer behave as normal. Otherwise, the same rules apply as the last time you worked +with this device. + +When the [1m[97minstruction pointer[0m is bound to a register, its value is written to that register just +before each instruction is executed, and the value of that register is written back to the +instruction pointer immediately after each instruction finishes execution. Afterward, move to the +next instruction by adding one to the instruction pointer, even if the value in the instruction +pointer was just updated by an instruction. (Because of this, instructions must effectively set the +instruction pointer to the instruction [1m[97mbefore[0m the one they want executed next.) + +The instruction pointer is 0 during the first instruction, 1 during the second, and so on. If the +instruction pointer ever causes the device to attempt to load an instruction outside the +instructions defined in the program, the program instead immediately halts. The instruction pointer +starts at 0. + +It turns out that this new information is already proving useful: the CPU in the device is not very +powerful, and a background process is occupying most of its time. You dump the background process' +declarations and instructions to a file (your puzzle input), making sure to use the names of the +opcodes rather than the numbers. + +For example, suppose you have the following program: + +#ip 0 +seti 5 0 1 +seti 6 0 2 +addi 0 1 0 +addr 1 2 3 +setr 1 0 0 +seti 8 0 4 +seti 9 0 5 + +When executed, the following instructions are executed. Each line contains the value of the +instruction pointer at the time the instruction started, the values of the six registers before +executing the instructions (in square brackets), the instruction itself, and the values of the six +registers after executing the instruction (also in square brackets). + +ip=0 [0, 0, 0, 0, 0, 0] seti 5 0 1 [0, 5, 0, 0, 0, 0] +ip=1 [1, 5, 0, 0, 0, 0] seti 6 0 2 [1, 5, 6, 0, 0, 0] +ip=2 [2, 5, 6, 0, 0, 0] addi 0 1 0 [3, 5, 6, 0, 0, 0] +ip=4 [4, 5, 6, 0, 0, 0] setr 1 0 0 [5, 5, 6, 0, 0, 0] +ip=6 [6, 5, 6, 0, 0, 0] seti 9 0 5 [6, 5, 6, 0, 0, 9] + +In detail, when running this program, the following events occur: + + + - The first line (#ip 0) indicates that the instruction pointer should be bound to register 0 in +this program. This is not an instruction, and so the value of the instruction pointer does not +change during the processing of this line. + + - The instruction pointer contains 0, and so the first instruction is executed (seti 5 0 1). It +updates register 0 to the current instruction pointer value (0), sets register 1 to 5, sets the +instruction pointer to the value of register 0 (which has no effect, as the instruction did not +modify register 0), and then adds one to the instruction pointer. + + - The instruction pointer contains 1, and so the second instruction, seti 6 0 2, is executed. This +is very similar to the instruction before it: 6 is stored in register 2, and the instruction pointer +is left with the value 2. + + - The instruction pointer is 2, which points at the instruction addi 0 1 0. This is like a +[1m[97mrelative jump[0m: the value of the instruction pointer, 2, is loaded into register 0. Then, addi finds +the result of adding the value in register 0 and the value 1, storing the result, 3, back in +register 0. Register 0 is then copied back to the instruction pointer, which will cause it to end up +1 larger than it would have otherwise and skip the next instruction (addr 1 2 3) entirely. Finally, +1 is added to the instruction pointer. + + - The instruction pointer is 4, so the instruction setr 1 0 0 is run. This is like an +[1m[97mabsolute jump[0m: it copies the value contained in register 1, 5, into register 0, which causes it to +end up in the instruction pointer. The instruction pointer is then incremented, leaving it at 6. + + - The instruction pointer is 6, so the instruction seti 9 0 5 stores 9 into register 5. The +instruction pointer is incremented, causing it to point outside the program, and so the program +ends. + + +[1m[97mWhat value is left in register 0[0m when the background process halts? + + diff --git a/src/19/part2 b/src/19/part2 new file mode 100644 index 0000000..3bfe430 --- /dev/null +++ b/src/19/part2 @@ -0,0 +1,58 @@ +--- Part Two --- + +You aren't sure how large Santa's ship is. You aren't even sure if you'll need to use this thing on +Santa's ship, but it doesn't hurt to be prepared. You figure Santa's ship might fit in a +[1m[97m100x100[0m square. + +The beam gets wider as it travels away from the emitter; you'll need to be a minimum distance away +to fit a square of that size into the beam fully. (Don't rotate the square; it should be aligned to +the same axes as the drone grid.) + +For example, suppose you have the following tractor beam readings: + +#....................................... +.#...................................... +..##.................................... +...###.................................. +....###................................. +.....####............................... +......#####............................. +......######............................ +.......#######.......................... +........########........................ +.........#########...................... +..........#########..................... +...........##########................... +...........############................. +............############................ +.............#############.............. +..............##############............ +...............###############.......... +................###############......... +................#################....... +.................########[1m[97mO[0mOOOOOOOOO..... +..................#######OOOOOOOOOO#.... +...................######OOOOOOOOOO###.. +....................#####OOOOOOOOOO##### +.....................####OOOOOOOOOO##### +.....................####OOOOOOOOOO##### +......................###OOOOOOOOOO##### +.......................##OOOOOOOOOO##### +........................#OOOOOOOOOO##### +.........................OOOOOOOOOO##### +..........................############## +..........................############## +...........................############# +............................############ +.............................########### + +In this example, the [1m[97m10x10[0m square closest to the emitter that fits entirely within the tractor beam +has been marked O. Within it, the point closest to the emitter (the only highlighted [1m[97mO[0m) is at X=25, +Y=20. + +Find the [1m[97m100x100[0m square closest to the emitter that fits entirely within the tractor beam; within +that square, find the point closest to the emitter. [1m[97mWhat value do you get if you take that point's +X coordinate, multiply it by 10000, then add the point's Y coordinate?[0m (In the example above, this +would be 250020.) + + diff --git a/src/19/solve.py b/src/19/solve.py new file mode 100644 index 0000000..c0c41eb --- /dev/null +++ b/src/19/solve.py @@ -0,0 +1,109 @@ +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 solve1(args):
+ global register, insptr
+ while register[inspaddr] < len(instructs):
+ insptr = register[inspaddr]
+ ins = instructs[insptr]
+ #aoc.debug(register)
+
+ # 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])
+
+ # increment instruction pointer
+ register[inspaddr] += 1
+
+ return register[0]
+
+
+alpha = [chr(c + ord('a')) for c in range(26)]
+
+dismap = dict()
+dismap["addr"] = lambda a, b : "%s + %s" % (alpha[a], alpha[b])
+dismap["addi"] = lambda a, b : "%s + %d" % (alpha[a], b)
+dismap["mulr"] = lambda a, b : "%s * %s" % (alpha[a], alpha[b])
+dismap["muli"] = lambda a, b : "%s * %d" % (alpha[a], b)
+dismap["banr"] = lambda a, b : str(alpha[a] & alpha[b])
+dismap["bani"] = lambda a, b : str(alpha[a] & b)
+dismap["borr"] = lambda a, b : str(alpha[a] | alpha[b])
+dismap["bori"] = lambda a, b : str(alpha[a] | b)
+dismap["setr"] = lambda a, b : str(alpha[a])
+dismap["seti"] = lambda a, b : str(a)
+dismap["gtir"] = lambda a, b : "(%d > %s)" % (a, alpha[b])
+dismap["gtri"] = lambda a, b : "(%s > %d)" % (alpha[a], b)
+dismap["gtrr"] = lambda a, b : "(%s > %s)" % (alpha[a], alpha[b])
+dismap["eqir"] = lambda a, b : "(%d == %s)" % (a, alpha[b])
+dismap["eqri"] = lambda a, b : "(%s == %d)" % (alpha[a], b)
+dismap["eqrr"] = lambda a, b : "(%s == %s)" % (alpha[a], alpha[b])
+
+def disassemble():
+ for i in range(len(instructs)):
+ ins = instructs[i]
+ aoc.debug(i ,":",alpha[ins[3]],"=", dismap[ins[0]](ins[1], ins[2]))
+ aoc.debug()
+
+""" divisor sum algo disassembled
+c = 1
+b = 1
+a = 0
+while b <= f:
+ c = 1
+ while c <= f:
+ if b * c == f:
+ a += b
+ c += 1
+ b += 1
+"""
+
+def solve2(args):
+ f = 10551276 # found by running
+
+ res = 0
+ sqrtf = sqrt(f)
+ for i in range(1, int(sqrtf)):
+ if f % i == 0:
+ res += i + f / i
+
+ if int(sqrtf) % f == 0:
+ res += sqrtf
+
+ return int(res)
+
+aoc.run(solve1, solve2, sols=[2072, 27578880])
diff --git a/src/19/test1 b/src/19/test1 new file mode 100644 index 0000000..d7d2a21 --- /dev/null +++ b/src/19/test1 @@ -0,0 +1,8 @@ +#ip 0 +seti 5 0 1 +seti 6 0 2 +addi 0 1 0 +addr 1 2 3 +setr 1 0 0 +seti 8 0 4 +seti 9 0 5 |
