diff --git a/11/11.py b/11/11.py new file mode 100755 index 0000000..1cc1bbf --- /dev/null +++ b/11/11.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python3 + +import sys + +# run with '2' argument for part2 result. +part2 = (len(sys.argv) == 2 and sys.argv[1] == '2') + +class IntComp: + def __init__(self, instructions, id): + self.instructions = instructions + self.pcounter = 0 + self.finished = 0 + self.ampid = id + self.inputs = [] + self.relbase = 0 + + def terminated(self): + return self.finished + + def r(self, pos, mode): + wantedpos = None + if mode == 0: + wantedpos = self.instructions[pos] + elif mode == 1: + wantedpos = pos + elif mode == 2: + wantedpos = self.relbase + self.instructions[pos] + else: + print ("Invalid mode!", mode) + exit(1) + + # Allow reading from 'new' memory. + if wantedpos >= len(self.instructions): + for i in range(len(self.instructions), wantedpos+1): + self.instructions.append(0) + + return int(self.instructions[wantedpos]) + + + def w(self, pos, v, mode): + wantedpos = None + if mode == 0: + wantedpos = self.instructions[pos] + elif mode == 1: + wantedpos = pos + elif mode == 2: + wantedpos = self.relbase + self.instructions[pos] + else: + print ("Invalid mode!", mode) + exit(1) + + # Allow writing to 'new' memory. + if wantedpos >= len(self.instructions): + for i in range(len(self.instructions), wantedpos+1): + self.instructions.append(0) + + self.instructions[wantedpos] = v + + def perform(self, inputs): + outputs = [] + + for inp in inputs: + self.inputs.append(inp) + + while 1: + fullopcode = self.instructions[self.pcounter] + opcode = fullopcode % 100 + mode_c = (int(fullopcode/100) % 10) + mode_b = (int(fullopcode/1000) % 10) + mode_a = (int(fullopcode/10000) % 10) + pos_c = self.pcounter+1 + pos_b = self.pcounter+2 + pos_a = self.pcounter+3 + + #print(self.ampid, "OP:", opcode, mode_c, mode_b, mode_a, pos_c, pos_b, pos_a) + + # add + if opcode == 1: + val = self.r(pos_c,mode_c) + self.r(pos_b,mode_b) + self.w(pos_a, val, mode_a) + self.pcounter += 4 + + # multiply + elif opcode == 2: + val = self.r(pos_c, mode_c) * self.r(pos_b, mode_b) + self.w(pos_a, val, mode_a) + self.pcounter += 4 + + # input + elif opcode == 3: + print ("input:", self.inputs) + store = self.inputs.pop(0) + self.w(pos_c, store, mode_c) + self.pcounter += 2 + + # output + elif opcode == 4: + outputs.append(self.r(pos_c, mode_c)) + self.pcounter += 2 + #print("output:", outputs) + return (outputs, self.finished) + + # jump-if-true + elif opcode == 5: + t = self.r(pos_c, mode_c) + if t != 0: + self.pcounter = self.r(pos_b, mode_b) + else: + self.pcounter += 3 + + # jump-if-false + elif opcode == 6: + t = self.r(pos_c, mode_c) + if t == 0: + self.pcounter = self.r(pos_b, mode_b) + else: + self.pcounter += 3 + + # less-than + elif opcode == 7: + c = self.r(pos_c, mode_c) + b = self.r(pos_b, mode_b) + if c < b: + self.w(pos_a, 1, mode_a) + else: + self.w(pos_a, 0, mode_a) + self.pcounter += 4 + + # equals + elif opcode == 8: + c = self.r(pos_c, mode_c) + b = self.r(pos_b, mode_b) + if c == b: + self.w(pos_a, 1, mode_a) + else: + self.w(pos_a, 0, mode_a) + self.pcounter += 4 + + # adjust-relbase + elif opcode == 9: + c = self.r(pos_c, mode_c) + self.relbase += c + self.pcounter += 2 + + # stop + elif opcode == 99: + self.finished = 1 + break + + return (outputs, self.finished) + +def turnleft(dir): + if dir == "U": + return "L" + elif dir == "L": + return "D" + elif dir == "D": + return "R" + elif dir == "R": + return "U" + +def turnright(dir): + if dir == "U": + return "R" + elif dir == "R": + return "D" + elif dir == "D": + return "L" + elif dir == "L": + return "U" + +def moverobot(pos, dir): + print("move:", pos) + if dir == "U": + pos[1] += 1 + elif dir == "L": + pos[0] -= 1 + elif dir == "D": + pos[1] -= 1 + elif dir == "R": + pos[0] += 1 + print("move->:", pos) + return pos + +for line in sys.stdin: + instructions = line.rstrip().split(',') + + ints = [] + grid = {0: {0: 0}} + + if part2: + grid[0][0] = 1 + + currentdir = "U" + currentpos = [0,0] + seen = {} + minX = None + maxX = None + minY = None + maxY = None + + for j in instructions: + ints.append(int(j)) + + robot = IntComp(ints,0) + + while not robot.terminated(): + #print("grid:", grid) + currentcolour = 0 + if currentpos[0] in grid: + if currentpos[1] in grid[currentpos[0]]: + currentcolour = grid[currentpos[0]][currentpos[1]] + print(">>", currentcolour) + + print("cc:", currentcolour, "pos:", currentpos, "dir:", currentdir) + + colour = robot.perform([currentcolour]) + if robot.terminated(): + continue + + # paint + if currentpos[0] in grid: + grid[currentpos[0]][currentpos[1]] = colour[0][0] + else: + t = {} + t[currentpos[1]] = colour[0][0] + grid[currentpos[0]] = t + xy = ("%d,%d" % (currentpos[0], currentpos[1])) + seen[xy] = 1 + + # turn + direction = robot.perform([]) + if direction[0][0] == 0: + print("LEFT") + currentdir = turnleft(currentdir) + else: + print("RIGHT") + currentdir = turnright(currentdir) + print("nc1:", colour[0][0], "npos", currentpos, "dir:", currentdir) + + # move + currentpos = moverobot(currentpos, currentdir) + print("nc2:", colour[0][0], "npos", currentpos, "dir:", currentdir) + print("==============") + + if minX is None or currentpos[0] < minX: + minX = currentpos[0] + if minY is None or currentpos[1] < minY: + minY = currentpos[1] + if maxX is None or currentpos[0] > maxX: + maxX = currentpos[0] + if maxY is None or currentpos[1] > maxY: + maxY = currentpos[1] + + if part2: + for y in range(maxY, minY-1, -1): + row = "" + for x in range(minX, maxX+1): + currentcolour = 0 + if x in grid: + if y in grid[x]: + currentcolour = grid[x][y] + if currentcolour == 1: + row = row + "#" + else: + row = row + " " + print(row) + + else: + print(len(seen)) +