class TractorBeam: def __init__(self, filename): self.program = read_int_list(filename) self.computer = IntcodeComputer(self.program.copy()) def read(self, x, y): return bool(self.computer.compute(deque([x, y])).pop()) def affected_in_50x50(self): return sum([self.read(*p) for p in product(range(50), repeat=2)]) def detect_100x100_square(self): start_cols = defaultdict(int) row = 0 while True: row += 1 start = start_cols[row - 1] for col in range(start, start + 50): if self.read(col, row): break else: continue start_cols[row] = col if (start_cols[col - 99] > 0 and self.read(col + 99, row) and col >= start_cols[col - 99] and self.read(col + 99, row - 99)): return col * 10000 + row - 99
from collections import defaultdict from myutils.file_reader import read_int_list from aoc2019.day09.d09 import IntcodeComputer prog = read_int_list('input.txt') for puzzle in [1, 2]: panels = defaultdict(bool) # false is black ic = IntcodeComputer(prog) if puzzle == 2: panels[(0, 0)] = True x, y = 0, 0 dx, dy = 0, -1 painted = set() while not ic.halted: input = 1 if panels[(x, y)] else 0 out = ic.step(input) code = out.popleft() move = out.popleft() if code == 0: panels[(x, y)] = False elif code == 1: panels[(x, y)] = True else: raise Exception('Invalid output code!') if puzzle == 1: painted.add((x, y)) if move == 0: dx, dy = dy, -dx
class OxygenSystem: def __init__(self, filename): self.program = read_int_list(filename) def reset(self): self.computer = IntcodeComputer(self.program.copy()) self.map = defaultdict(int) # 0: unknown, 1: open, -1: blocked def display_map(self): minx = miny = -5 maxx = maxy = 5 for x, y in self.map.keys(): minx = min(minx, x) maxx = max(maxx, x) miny = min(miny, y) maxy = max(maxy, y) os.system('clear') print() for j in range(miny, maxy + 1): for i in range(minx, maxx + 1): if (i, j) == self.oxygen: ch = 'O' elif j == self.y and i == self.x: ch = 'd' else: m = self.map[(i, j)] if m > 0: ch = '.' elif m < 0: ch = '#' else: ch = ' ' print(ch, end='') print() time.sleep(0.05) def neighbours(self, x, y): return [(x + i, y + j) for i, j in [(-1, 0), (1, 0), (0, -1), (0, 1)]] def moves_to(self, target): conn = dict() q = deque([target]) while q: c = q.popleft() x, y = c for n in self.neighbours(x, y): if self.map[n] > 0 and n not in conn: conn[n] = c if n == (self.x, self.y): q.clear() break q.append(n) result = deque() c = (self.x, self.y) while c != target: n = conn[c] if n[0] > c[0]: result.append(4) elif n[1] > c[1]: result.append(2) elif n[0] < c[0]: result.append(3) elif n[1] < c[1]: result.append(1) else: raise Exception('unknown move') c = n return result def navigate(self, display=False): self.reset() self.x = self.y = 0 self.map[(0, 0)] = 1 to_visit = deque([(0, 1)]) # first must see neighbor tape = deque() self.oxygen = None while to_visit: to_visit = deque([p for p in to_visit if self.map[p] == 0]) ns = [ n for n in self.neighbours(self.x, self.y) if self.map[n] == 0 ] to_visit.extend(ns) while not tape: tape = self.moves_to(to_visit.pop()) move = tape.popleft() output = self.computer.step(move) if len(output) != 1: raise Exception('invalid output') output = output[0] if move == 1: dest = (self.x, self.y - 1) elif move == 2: dest = (self.x, self.y + 1) elif move == 3: dest = (self.x - 1, self.y) elif move == 4: dest = (self.x + 1, self.y) else: raise Exception('invalid move') if output == 0: self.map[dest] = -1 else: self.map[dest] = 1 self.x, self.y = dest if output == 2: self.oxygen = dest if display: self.display_map() return def calc_oxygen_distance(self): self.x, self.y = self.oxygen return len(self.moves_to((0, 0))) def calc_filling_time(self): q = [self.oxygen] self.map[self.oxygen] = 2 t = 0 while True: newq = [] for c in q: for n in self.neighbours(*c): if self.map[n] == 1: newq.append(n) self.map[n] = 2 if newq: t += 1 q = newq else: return t
def reset(self): self.computer = IntcodeComputer(self.program.copy()) self.map = defaultdict(int) # 0: unknown, 1: open, -1: blocked
class CarePackage: def __init__(self, filename): self.program = read_int_list(filename) def reset(self): self.computer = IntcodeComputer(self.program) self.board = defaultdict(int) self.score = 0 self.ball_x = 0 self.paddle_x = 0 def apply_output(self, out): while out: x, y, obj = out.popleft(), out.popleft(), out.popleft() if x >= 0: self.board[(y, x)] = obj if obj == 3: self.paddle_x = x elif obj == 4: self.ball_x = x else: self.score = obj def read_board(self): self.apply_output(self.computer.step()) def play_move(self, input): self.apply_output(self.computer.step(input)) def count_blocks(self): self.reset() self.read_board() count = 0 for v in self.board.values(): if v == 2: count += 1 return count @staticmethod def display_char(object): if object == 0: print(' ', end='') elif object == 1: print('#', end='') elif object == 2: print('x', end='') elif object == 3: print('T', end='') elif object == 4: print('o', end='') def display_board(self): xmin = xmax = ymin = ymax = 0 for k in self.board.keys(): y, x = k xmin = min(xmin, x) xmax = max(xmax, x) ymin = min(ymin, y) ymax = max(ymax, y) os.system('clear') print(f'Score: {self.score}') for y in range(ymin, ymax + 1): for x in range(xmin, xmax + 1): self.display_char(self.board[(y, x)]) print() def play_arcade(self, display=False): self.reset() self.read_board() self.computer.program[0] = 2 self.computer.halted = False while not self.computer.halted: if display: self.display_board() time.sleep(0.04) diff = self.ball_x - self.paddle_x if diff == 0: input = 0 elif diff > 0: input = 1 else: input = -1 self.play_move(input) return self.score
def reset(self): self.computer = IntcodeComputer(self.program) self.board = defaultdict(int) self.score = 0 self.ball_x = 0 self.paddle_x = 0
def __init__(self, filename): self.program = read_int_list(filename) self.computer = IntcodeComputer(self.program.copy())
def reset(self): self.computer = IntcodeComputer(self.program.copy())
class SetAndForget: def __init__(self, filename): self.program = read_int_list(filename) def reset(self): self.computer = IntcodeComputer(self.program.copy()) def analyze_output(self, input, just_final_output=False): output = self.computer.compute(input) if just_final_output: return output.pop() output = ''.join(map(chr, output)) self.map = defaultdict(int) # 0: ., 1: # row, col = 0, 0 self.cols = 0 for cell in output: if cell == '\n': if self.cols == 0: self.cols = col col = 0 row += 1 continue if cell in 'v^><': self.y, self.x = row, col if cell == '^': self.dy, self.dx = -1, 0 elif cell == 'v': self.dy, self.dx = 1, 0 elif cell == '<': self.dy, self.dx = 0, -1 elif cell == '>': self.dy, self.dx = 0, 1 elif cell == '#': self.map[(row, col)] = 1 elif cell == '.': self.map[(row, col)] = 0 else: break col += 1 self.rows = row print(output) def alignment(self): self.reset() self.analyze_output([]) mask = [[0, 0], [-1, 0], [1, 0], [0, -1], [0, 1]] total = 0 for cell in list(self.map.keys()): y, x = cell for mask_cell in mask: dy, dx = mask_cell if not self.map[(y + dy, x + dx)]: break else: total += x * y self.map[(y, x)] = 2 return total def calculate_plain_program(self): input = [] map = self.map.copy() y, x = self.y, self.x dy, dx = self.dy, self.dx fc = 0 while True: rcount = 0 while map[(y + dy, x + dx)] == 0 and rcount < 4: dy, dx = -dx, dy rcount += 1 if rcount == 0: fc += 1 y += dy x += dx map[(y, x)] -= 1 else: if fc: input.append(str(fc)) fc = 0 if rcount == 1: input.append('L') elif rcount == 3: input.append('R') elif rcount == 4: break else: raise Exception('Rotated Back!') return input def cleaning(self): self.program[0] = 2 self.reset() input = self.calculate_plain_program() print(','.join(input)) # Manually analyzed! input = \ 'A,A,C,B,C,B,C,B,B,A\n'\ 'L,10,R,8,R,8\n'\ 'R,10,L,12,R,10\n'\ 'L,10,L,12,R,8,R,10\n'\ 'n\n' input = deque(map(ord, input)) collected = \ self.analyze_output( input, just_final_output=True) print(f'Collected Dust: {collected}')