class Droid: """ Executes the given intcode program, to navigate through damaged hull""" def __init__(self, intcode: List[int]): self.intcode = intcode self.result = [] self.instruction = None def to_ascii(self, instruction: str) -> List[int]: ascii_instruction = [ord(char) for char in instruction] return ascii_instruction + [10] def get_input(self): try: value = next(self.instruction) except : self.instruction = (ascii_char for ascii_char in self.to_ascii(input())) value = next(self.instruction) return value def generate_output(self, value: int): try : self.result.append(chr(value)) except: self.result.append(str(value)) print(''.join(self.result)) def execute(self): self.intcode_computer = IntcodeComputer(self.intcode, self.get_input, self.generate_output) while self.intcode_computer.has_next(): next(self.intcode_computer.process_intcode())
class SpringDroid: """ Executes the given intcode program, to navigate through damaged hull""" def __init__(self, intcode: List[int]): self.intcode = intcode # Jum if : # - 4 is ground # - AND (1 empty or 2 empty or 3 empty) # - AND (5 is ground or 8 is ground) self.program = ['NOT A T','NOT B J','OR J T','NOT C J','OR T J', 'AND D J', 'NOT E T','NOT T T', 'OR H T', 'AND T J', 'RUN'] self.result = [] self.instructions = (ascii_char for line in self.program for ascii_char in self.to_ascii(line) ) def to_ascii(self, instruction: str) -> List[int]: ascii_instruction = [ord(char) for char in instruction] return ascii_instruction + [10] def get_input(self): return next(self.instructions) def generate_output(self, value: int): try : self.result.append(chr(value)) except: self.result.append(str(value)) def execute(self): self.intcode_computer = IntcodeComputer(self.intcode, self.get_input, self.generate_output) while self.intcode_computer.has_next(): next(self.intcode_computer.process_intcode())
class Drone: """ Executes the given intcode program, to play a game""" def __init__(self, intcode: List[int]): self.intcode = intcode self.x = NotImplemented self.y = None self.give_x = True self.scanning = (None,None) self.current_position = (self.x, self.y) self.tractor_area = defaultdict(int) self.moves = {1: (0,1), 2:(0,-1), 4:(1,0), 3:(-1,0)} self.input_x = (x for point in zip(range(50), range(50)) for x in point) def get_input(self): print(f"Giving {self.x, self.y}") if self.give_x: self.give_x = False return self.x else: self.give_x = True return self.y def generate_output(self, value: int): print(f"Got {value} on {self.x, self.y}") self.tractor_area[(self.x, self.y)] = value def execute(self): self.intcode_computer = IntcodeComputer(self.intcode, self.get_input, self.generate_output) while self.intcode_computer.has_next(): next(self.intcode_computer.process_intcode()) def execute_for_grid(self, max_x: int, max_y: int): for y in range(max_y): self.y = y for x in range(max_x): self.x = x self.execute() def curses_display(self, stdscr): stdscr.clear() stdscr.refresh() x,y = zip(*self.tractor_area.keys()) xmin, xmax = min(x), max(x) ymin, ymax = min(y), max(y) for x in range(xmin, xmax + 1): for y in range(ymin, ymax + 1): block = self.tractor_area[(x,y)] character = "#" if block == 0 else "." stdscr.addstr(abs(x - xmin),abs(y - ymin), character) stdscr.refresh() def command_line_display(self): x,y = zip(*self.tractor_area.keys()) xmin, xmax = min(x), max(x) ymin, ymax = min(y), max(y) for y in range(ymin, ymax + 1): string = [f"{y:02d}"] for x in range(xmin, xmax + 1): if (x,y) not in self.tractor_area.keys(): print(f"Possible error at {x,y}") block = self.tractor_area[(x,y)] string.append('#' if block == 1 else '.') print(''.join(string))
class VacuumRobot: """ Executes the given intcode program, to play a game""" def __init__(self, intcode: List[int]): self.intcode = intcode self.x = 0 self.y = 0 self.current_position = (self.x, self.y) self.search_space = defaultdict(int) self.intcode_computer = IntcodeComputer(intcode, self.get_input, self.generate_output) self.moves = {1: (0,1), 2:(0,-1), 4:(1,0), 3:(-1,0)} self.alignment_points = [] self.input = 1 self.routine_index = 0 self.main_rutine = [ord('A'), 44, ord('A'), 44, ord('B'), 44, ord('C'), 44, ord('B'), 44, ord('C'), 44, ord('B'), 44, ord('C'), 44, ord('B'), 44, ord('A'), 10] self.A = [ord('R'), 44, ord('6'), 44, ord('L'), 44, ord('1'), ord('2'), 44, ord('R'), 44, ord('6'), 10] self.B = [ord('L'), 44, ord('1'), ord('2'), 44, ord('R'), 44, ord('6'), 44, ord('L'), 44, ord('8'), 44, ord('L'), 44, ord('1'), ord('2'), 10] self.C = [ord('R'), 44, ord('1'), ord('2'), 44, ord('L'), 44, ord('1'), ord('0'), 44, ord('L'), 44, ord('1'), ord('0'), 10] self.video_feed = [110, 10] self.routines = self.A + self.B + self.C self.colllected_dust = [] def get_input(self): if self.input == 1: value = self.main_rutine[self.routine_index] self.routine_index += 1 if self.routine_index == len(self.main_rutine): self.routine_index = 0 self.input = 2 return value elif self.input == 2: value = self.routines[self.routine_index] self.routine_index += 1 if self.routine_index == len(self.routines): self.routine_index = 0 self.input = 3 return value elif self.input == 3: value = self.video_feed[self.routine_index] self.routine_index += 1 return value return 0 def generate_output(self, value: int): self.colllected_dust.append(value) def get_alignments(self): for position, value in self.search_space.items(): if value == 1 and len(self.valid_positions(position)) >= 3: logging.warning(f"Found alignment point at {position}") self.alignment_points.append(position) def get_alignments_value(self): return sum(x * y for x,y in self.alignment_points) def execute(self): while self.intcode_computer.has_next(): next(self.intcode_computer.process_intcode()) def next_position(self, mov, pos = None) -> Pos: if mov == 1: return (pos[0], pos[1] +1) elif mov == 2: return (pos[0], pos[1] -1) elif mov == 3: return (pos[0] + 1, pos[1]) elif mov == 4: return (pos[0] - 1, pos[1]) def next_robot_position(self, robot_pos, robot_orientation) -> Pos: if robot_orientation == 2: return (robot_pos[0], robot_pos[1] - 1) elif robot_orientation == 3: return (robot_pos[0] -1, robot_pos[1]) elif robot_orientation == 4: return (robot_pos[0] + 1, robot_pos[1]) elif robot_orientation == 5: return (robot_pos[0], robot_pos[1] + 1) def get_next_orientation(self, orientation, turn): if turn == 'L': if orientation == 2: return 3 elif orientation == 3: return 5 elif orientation == 4: return 2 elif orientation == 5: return 4 elif turn == 'R': if orientation == 2: return 4 elif orientation == 3: return 2 elif orientation == 4: return 5 elif orientation == 5: return 3 def valid_positions(self, pos): valid_pos = [] for mov in self.moves.keys(): next_cell = self.next_position(mov, pos) if next_cell in self.search_space.keys() and self.search_space[next_cell] == 1: valid_pos.append(next_cell) return valid_pos def curses_display(self, stdscr): stdscr.clear() stdscr.refresh() x,y = zip(*self.search_space.keys()) xmin, xmax = min(x), max(x) ymin, ymax = min(y), max(y) for x in range(xmin, xmax + 1): for y in range(ymin, ymax + 1): block = self.search_space[(x,y)] character = "#" if block == 0 else "." stdscr.addstr(abs(x - xmin),abs(y - ymin), character) stdscr.refresh() def greedy_solver(self): robot_pos = self.robot_pos robot_orientation = 2 total_scaffold = sum(v for v in self.search_space.values() if v == 1) print(f"Total scaffold to cover {total_scaffold}") covered = 0 movements = [] while covered < total_scaffold: avance = 0 next_robot_pos = self.next_robot_position(robot_pos, robot_orientation) while self.search_space[next_robot_pos] == 1: avance += 1 robot_pos = next_robot_pos next_robot_pos = self.next_robot_position(robot_pos, robot_orientation) print(f"Advanced {avance}, covered {covered}") avance += 1 movements.append(avance) covered += avance avance = 0 next_robot_orientation = self.get_next_orientation(robot_orientation, 'L') next_robot_pos = self.next_robot_position(robot_pos, next_robot_orientation) if self.search_space[next_robot_pos] == 1: robot_pos = next_robot_pos robot_orientation = next_robot_orientation movements.append('L') print(f"Turning left") else: next_robot_orientation = self.get_next_orientation(robot_orientation, 'R') next_robot_pos = self.next_robot_position(robot_pos, next_robot_orientation) if self.search_space[next_robot_pos] == 1: robot_pos = next_robot_pos robot_orientation = next_robot_orientation movements.append('R') print(f"Turning right") else: raise("Dead end") return movements def command_line_display(self): x,y = zip(*self.search_space.keys()) xmin, xmax = min(x), max(x) ymin, ymax = min(y), max(y) for y in range(ymin, ymax + 1): string = [f"{y:02d}"] for x in range(xmin, xmax + 1): if (x,y) not in self.search_space.keys(): print(f"Possible error at {x,y}") block = self.search_space[(x,y)] if (x,y) in self.alignment_points: string.append('O') elif block == 2: string.append('>') else: string.append("#" if block == 1 else ".") print(''.join(string))
class Drone: """ Executes the given intcode program, to play a game""" def __init__(self, intcode: List[int]): self.intcode = intcode self.current_position = (0, 0) self.search_space = defaultdict(int) self.search_space[self.current_position] = -1 self.unvisited_nodes = set() self.explored = defaultdict(int) self.solution_path = [] self.image = None self.intcode_computer = IntcodeComputer(intcode, self.get_input, self.generate_output) self.moves = {1: (0, 1), 2: (0, -1), 4: (1, 0), 3: (-1, 0)} def get_input(self): return self.input def generate_output(self, value: int): print(f"Got {value}") temptative_positon = self.next_position(self.input) self.search_space[temptative_positon] = value if value != 0: self.current_position = temptative_positon def execute(self): while self.intcode_computer.has_next(): next(self.intcode_computer.process_intcode()) def next_position(self, mov) -> Pos: if mov == 1: return (self.current_position[0], self.current_position[1] + 1) elif mov == 2: return (self.current_position[0], self.current_position[1] - 1) elif mov == 3: return (self.current_position[0] + 1, self.current_position[1]) elif mov == 4: return (self.current_position[0] - 1, self.current_position[1]) def step_back(self): # Remove step from solution path print(f"Found dead end, stepping back from {self.current_position}") last_move = self.solution_path.pop() # Undo step if last_move == 1: self.input = 2 elif last_move == 2: self.input = 1 elif last_move == 3: self.input = 4 elif last_move == 4: self.input = 3 self.intcode_computer.step() def step_forward(self, mov) -> bool: self.input = mov self.solution_path.append(mov) self.intcode_computer.step() def explore(self, mov, next_pos): print(f"Trying {mov} from {self.current_position}") self.step_forward(mov) if self.search_space[next_pos] == 2: print( f"Solution found at {next_pos} in {len(self.solution_path)} steps" ) print(self.solution_path) self.display_screen() return True elif self.search_space[next_pos] == 0: # Hit a wall, remove step from solution path self.solution_path.pop() return False else: self.explored[self.current_position] = 1 for mov in self.moves.keys(): next_pos = self.next_position(mov) if self.explored[next_pos] == 0: found = self.explore(mov, next_pos) if found: return True self.step_back() return False def command_line_display(self, image): for x in range(image.shape[0]): string = [] for y in range(image.shape[1]): if image[x, y] == -1: string.append('@') if image[x, y] == 0: string.append('#') if image[x, y] == 1: string.append('X') if image[x, y] == 2: string.append('*') if image[x, y] == 3: string.append('.') print(''.join(string)) def display_screen(self): # if self.image is None: self.min_x = min(key[0] for key in self.search_space.keys()) max_x = max(key[0] for key in self.search_space.keys()) min_y = min(key[1] for key in self.search_space.keys()) self.max_y = max(key[1] for key in self.search_space.keys()) size_x = max_x - self.min_x size_y = self.max_y - min_y self.image = np.ones(shape=(size_y + 1, size_x + 1)) * 3 for position, color in self.search_space.items(): # Correct coordinates. In the array (0,0) is top left if position == (0, 0): color = -1 self.image[abs(position[1] - self.max_y), abs(position[0] - self.min_x)] = color self.command_line_display(self.image)
class Drone: """ Executes the given intcode program, to play a game""" def __init__(self, intcode: List[int]): self.intcode = intcode self.x = 0 self.y = 0 self.give_x = True self.tractor_area = defaultdict(int) def get_input(self): # print(f"Giving {self.x, self.y}") if self.give_x: self.give_x = False return self.x else: self.give_x = True return self.y def generate_output(self, value: int): # print(f"Got {value} on {self.x, self.y}") self.tractor_area[(self.x, self.y)] = value def execute(self): self.intcode_computer = IntcodeComputer(self.intcode, self.get_input, self.generate_output) while self.intcode_computer.has_next(): next(self.intcode_computer.process_intcode()) def manual_execute(self): user_input = input().split() self.x, self.y = int(user_input[0]), int(user_input[1]) while self.x != 'q': self.intcode_computer = IntcodeComputer(self.intcode, self.get_input, self.generate_output) while self.intcode_computer.has_next(): next(self.intcode_computer.process_intcode()) user_input = input().split() self.x, self.y = int(user_input[0]), int(user_input[1]) def find_first_one_in_line(self, line: int): start = 1 found = False end = line self.y = line while not found: self.x = start + (end - start) // 2 + 1 self.execute() if self.tractor_area[(self.x, self.y)] == 1: self.x -= 1 self.execute() if self.tractor_area[(self.x, self.y)] == 0: # print(f"Found at {self.x,self.y}") found = True end = self.x else: start = self.x return self.x + 1 def check_santa_ship_fit(self, x, y, ship_len): self.y = self.y - ship_len + 1 self.x = x + ship_len - 1 self.execute() return self.tractor_area[(self.x, self.y)] == 1 def search_first_len(self, ship_len): # Try line Y # Find first 1 in line Y # Check if 100 above is also 1, check if 100 right is also one start = ship_len end = None end_found = False found = False candidate_x = None candidate_y = None while not found: if not end_found: self.y = start * 2 else: self.y = start + (end - start) // 2 + 1 print(f" **** Trying y={self.y} ****") first_x_one = self.find_first_one_in_line(self.y) candidate_y = self.y candidate_x = first_x_one print(f"first 1 in line {self.y}: {first_x_one}") if self.check_santa_ship_fit(first_x_one, self.y, ship_len): print( f" **** Found candidate at x={first_x_one} y={candidate_y} ****" ) end_found = True found = True end = candidate_y for i in range(1, 2): first_x_one = self.find_first_one_in_line(candidate_y - i) if not self.check_santa_ship_fit( first_x_one, candidate_y - 1, ship_len): pass else: print( f"***** Counter at {first_x_one,candidate_y- i} ******" ) found = False if found == True: print(f"***** Found at {candidate_x,candidate_y} ******") else: start = candidate_y return candidate_x, candidate_y - ship_len + 1 def execute_for_grid(self, max_x: int, max_y: int): for y in range(max_y): self.y = y for x in range(max_x): self.x = x self.execute() def command_line_display(self): x, y = zip(*self.tractor_area.keys()) xmin, xmax = min(x), max(x) ymin, ymax = min(y), max(y) for y in range(ymin, ymax + 1): string = [f"{y:02d}"] for x in range(xmin, xmax + 1): if (x, y) not in self.tractor_area.keys(): print(f"Possible error at {x,y}") block = self.tractor_area[(x, y)] string.append('#' if block == 1 else '.') print(''.join(string))