def find_noun_verb_pair(): for noun in range(100): for verb in range(100): code = get_code(noun, verb) computer = IntcodeComputer() computer.execute_program(code) if code[0] == 19690720: return noun, verb
class PaintingRobot: def __init__(self, input_file=None, echo=True): if input_file: self.computer = IntcodeComputer(input_file, echo=echo) else: self.computer = IntcodeComputer(echo=echo) # 0 UP, 1 RIGHT, 2 DOWN, 3 LEFT self.direction = 0 self.position = (0, 0) self.painted_tiles = {} self.echo = echo def run(self): self.paint_tile(self.position, 1) running = True while running: color = self.get_tile_color(self.position) self.computer.set_input([color]) self.computer.execute_program() output = self.computer.get_output_values() self.paint_tile(self.position, output[0]) if output[1] == 0: self.rotate_left() elif output[1] == 1: self.rotate_right() else: print('Error: Invalid rotation direction') break self.move_forward() if self.computer.finished: running = False print('Robot is finished') num_tiles = len(self.painted_tiles) print('Num tiles painted %d' % num_tiles) def rotate_left(self): self.direction -= 1 if self.direction < 0: self.direction = 3 if self.echo: print('Rotating Left. New direction %d' % self.direction) def rotate_right(self): self.direction += 1 if self.direction > 3: self.direction = 0 if self.echo: print('Rotating Right. New direction %d' % self.direction) def move_forward(self): move_x, move_y = 0, 0 if self.direction == 0: move_y = -1 elif self.direction == 1: move_x = 1 elif self.direction == 2: move_y = 1 elif self.direction == 3: move_x = -1 pos_x, pos_y = self.position self.position = pos_x + move_x, pos_y + move_y if self.echo: print('Moving to position (%d, %d)' % (self.position[0], self.position[1])) def get_tile_color(self, tile_pos): if tile_pos not in self.painted_tiles: return 0 else: return self.painted_tiles[tile_pos] def paint_tile(self, tile_pos, color): self.painted_tiles[tile_pos] = color if self.echo: print('Painting tile (%d, %d) color %d' % (tile_pos[0], tile_pos[1], color)) def output_tiles(self): min_x, max_x = None, None min_y, max_y = None, None for key in self.painted_tiles: if min_x is None or key[0] < min_x: min_x = key[0] if max_x is None or key[0] > max_x: max_x = key[0] if min_y is None or key[1] < min_y: min_y = key[1] if max_y is None or key[1] > max_y: max_y = key[1] for y in range(min_y, max_y + 1): for x in range(min_x, max_x + 1): pos = x, y if pos in self.painted_tiles and self.painted_tiles[pos] == 1: print('#', end='') else: print(' ', end='') print('\n', end='')
def part_two(): code = get_code() computer = IntcodeComputer() computer.set_input(5) computer.execute_program(code)
def part_one(): code = get_code(12, 2) computer = IntcodeComputer() computer.execute_program(code) print(code[0])
class ArcadeCabinet: def __init__(self, file=None, echo=True): if file is None: self.computer = IntcodeComputer(echo=echo) else: self.computer = IntcodeComputer(file, echo=echo) self.width, self.height = 0, 0 self.grid = [] def run(self): self.computer.execute_program() output = self.computer.get_output_values() for i in range(0, len(output), 3): x = output[i] y = output[i+1] tile = output[i+2] self.set_tile(x, y, tile) self.print_grid() print('Number Blocks: %d' % self.count_blocks()) def set_tile(self, x, y, tile): if not self.in_bounds(x, y): self.expand_grid(x+1, y+1) self.grid[x][y] = tile def in_bounds(self, x, y): if x >= self.width or y >= self.height: return False else: return True def expand_grid(self, new_width, new_height): if new_width > self.width: add_width = new_width - self.width for i in range(add_width): self.grid.append([0 for tile in range(self.height)]) self.width = new_width if new_height > self.height: add_height = new_height - self.height for column in self.grid: column.extend([0 for tile in range(add_height)]) self.height = new_height def print_grid(self): for y in range(self.height): for x in range(self.width): tile = self.grid[x][y] print(tile, end='') print('\n', end='') def count_blocks(self): block_count = 0 for y in range(self.height): for x in range(self.width): tile = self.grid[x][y] if tile == 2: block_count += 1 return block_count
class DroidController: def __init__(self, file_str, echo=True): self.computer = IntcodeComputer(file_str, echo=False) self.x, self.y = 0, 0 self.min_x, self.max_x = 0, 0 self.min_y, self.max_y = 0, 0 self.map = {(self.x, self.y): '.'} self.path = [] self.target = None def print_map(self): for y in range(self.min_y, self.max_y + 1): for x in range(self.min_x, self.max_x + 1): if (x, y) in self.map: if (self.x, self.y) == (x, y): print('D', end='') else: tile = self.map[(x, y)] print(tile, end='') else: print(' ', end='') # New Line print('\n', end='') def find_all_unexplored(self): # Find all unexplored tiles all_unexplored = [] for coord in self.map: tile = self.map[coord] if tile == '.' or tile == 'O': unexplored = self.check_unexplored(coord) all_unexplored.extend(unexplored) return all_unexplored def find_nearest_unexplored(self): ''' Returns the (x, y) coordinate of the nearest manhatten distance unexplored tile from self.pos. ''' all_unexplored = self.find_all_unexplored() # Find distance of each tile distances = [] for tile in all_unexplored: dist_x = abs(self.x - tile[0]) dist_y = abs(self.y - tile[1]) distances.append(dist_x + dist_y) # Find shortest distance min_i = -1 min_dist = -1 for i, dist in enumerate(distances): if min_dist is -1 or dist < min_dist: min_i = i min_dist = dist return all_unexplored[min_i] def find_oxygen_system(self): for coord in self.map: if self.map[coord] == 'O': return coord return None def find_max_dist_from_oxygen(self): start = self.find_oxygen_system() if start is None: print('Oxygen System not found') return None # Search for finish from start tile_list = [start] parents = {start: None} distances = {start: 0} while len(tile_list) > 0: tile = tile_list.pop(0) tile_x, tile_y = tile tile_dist = distances[tile] if tile not in self.map: continue # Add neighbors to list if not explored or smaller distance ## Up tile_up = tile_x, tile_y - 1 if tile_up in parents: # Already searched tile. Check for shorter distance tile_up_dist = distances[tile_up] if tile_up_dist > tile_dist + 1: if tile_up in self.map: tile_list.append(tile_up) parents[tile_up] = tile distances[tile_up] = tile_dist + 1 elif tile_up in self.map: # Nonsearched explored tile. Add to list if not a wall if self.map[tile_up] != '#': tile_list.append(tile_up) parents[tile_up] = tile distances[tile_up] = tile_dist + 1 else: # Nonsearched unexplored tile. Add to path but not the search list parents[tile_up] = tile distances[tile_up] = tile_dist + 1 ## Down tile_down = tile_x, tile_y + 1 if tile_down in parents: # Already searched tile. Check for shorter distance tile_down_dist = distances[tile_down] if tile_down_dist > tile_dist + 1: if tile_down in self.map: tile_list.append(tile_down) parents[tile_down] = tile distances[tile_down] = tile_dist + 1 elif tile_down in self.map: # Nonsearched explored tile. Add to list if not a wall if self.map[tile_down] != '#': tile_list.append(tile_down) parents[tile_down] = tile distances[tile_down] = tile_dist + 1 else: # Nonsearched unexplored tile. Add to path but not the search list parents[tile_down] = tile distances[tile_down] = tile_dist + 1 ## Left tile_left = tile_x - 1, tile_y if tile_left in parents: # Already searched tile. Check for shorter distance tile_left_dist = distances[tile_left] if tile_left_dist > tile_dist + 1: if tile_left in self.map: tile_list.append(tile_left) parents[tile_left] = tile distances[tile_left] = tile_dist + 1 elif tile_left in self.map: # Nonsearched explored tile. Add to list if not a wall if self.map[tile_left] != '#': tile_list.append(tile_left) parents[tile_left] = tile distances[tile_left] = tile_dist + 1 else: # Nonsearched unexplored tile. Add to path but not the search list parents[tile_left] = tile distances[tile_left] = tile_dist + 1 ## Right tile_right = tile_x + 1, tile_y if tile_right in parents: # Already searched tile. Check for shorter distance tile_right_dist = distances[tile_right] if tile_right_dist > tile_dist + 1: if tile_right in self.map: tile_list.append(tile_right) parents[tile_right] = tile distances[tile_right] = tile_dist + 1 elif tile_right in self.map: # Nonsearched explored tile. Add to list if not a wall if self.map[tile_right] != '#': tile_list.append(tile_right) parents[tile_right] = tile distances[tile_right] = tile_dist + 1 else: # Nonsearched unexplored tile. Add to path but not the search list parents[tile_right] = tile distances[tile_right] = tile_dist + 1 max_dist = 0 for tile in distances: if distances[tile] > max_dist: max_dist = distances[tile] return max_dist def check_unexplored(self, coord): ''' Returns a list of (x, y) coordinates containing unexplored tiles in 4 cardinal directions of given coordinate ''' unexplored = [] x, y = coord # Top tile_up = x, y - 1 if tile_up not in self.map: unexplored.append(tile_up) # Bottom tile_down = x, y + 1 if tile_down not in self.map: unexplored.append(tile_down) # Left tile_left = x - 1, y if tile_left not in self.map: unexplored.append(tile_left) # Right tile_right = x + 1, y if tile_right not in self.map: unexplored.append(tile_right) return unexplored def find_path_to_target(self, start, finish): # print('Finding path from %s to %s' % (start, finish)) # Search for finish from start tile_list = [start] parents = {start: None} distances = {start: 0} while len(tile_list) > 0: tile = tile_list.pop(0) tile_x, tile_y = tile tile_dist = distances[tile] if tile not in self.map: continue # Add neighbors to list if not explored or smaller distance ## Up tile_up = tile_x, tile_y - 1 if tile_up in parents: # Already searched tile. Check for shorter distance tile_up_dist = distances[tile_up] if tile_up_dist > tile_dist + 1: if tile_up in self.map: tile_list.append(tile_up) parents[tile_up] = tile distances[tile_up] = tile_dist + 1 elif tile_up in self.map: # Nonsearched explored tile. Add to list if not a wall if self.map[tile_up] != '#': tile_list.append(tile_up) parents[tile_up] = tile distances[tile_up] = tile_dist + 1 else: # Nonsearched unexplored tile. Add to path but not the search list parents[tile_up] = tile distances[tile_up] = tile_dist + 1 ## Down tile_down = tile_x, tile_y + 1 if tile_down in parents: # Already searched tile. Check for shorter distance tile_down_dist = distances[tile_down] if tile_down_dist > tile_dist + 1: if tile_down in self.map: tile_list.append(tile_down) parents[tile_down] = tile distances[tile_down] = tile_dist + 1 elif tile_down in self.map: # Nonsearched explored tile. Add to list if not a wall if self.map[tile_down] != '#': tile_list.append(tile_down) parents[tile_down] = tile distances[tile_down] = tile_dist + 1 else: # Nonsearched unexplored tile. Add to path but not the search list parents[tile_down] = tile distances[tile_down] = tile_dist + 1 ## Left tile_left = tile_x - 1, tile_y if tile_left in parents: # Already searched tile. Check for shorter distance tile_left_dist = distances[tile_left] if tile_left_dist > tile_dist + 1: if tile_left in self.map: tile_list.append(tile_left) parents[tile_left] = tile distances[tile_left] = tile_dist + 1 elif tile_left in self.map: # Nonsearched explored tile. Add to list if not a wall if self.map[tile_left] != '#': tile_list.append(tile_left) parents[tile_left] = tile distances[tile_left] = tile_dist + 1 else: # Nonsearched unexplored tile. Add to path but not the search list parents[tile_left] = tile distances[tile_left] = tile_dist + 1 ## Right tile_right = tile_x + 1, tile_y if tile_right in parents: # Already searched tile. Check for shorter distance tile_right_dist = distances[tile_right] if tile_right_dist > tile_dist + 1: if tile_right in self.map: tile_list.append(tile_right) parents[tile_right] = tile distances[tile_right] = tile_dist + 1 elif tile_right in self.map: # Nonsearched explored tile. Add to list if not a wall if self.map[tile_right] != '#': tile_list.append(tile_right) parents[tile_right] = tile distances[tile_right] = tile_dist + 1 else: # Nonsearched unexplored tile. Add to path but not the search list parents[tile_right] = tile distances[tile_right] = tile_dist + 1 # Find path back to start new_path = [] if finish in parents: path_node = finish while path_node != start: new_path.insert(0, path_node) path_node = parents[path_node] # print('Found Path: %s' % str(new_path)) # print(new_path) return new_path def move_on_path(self): if self.path == []: print('Error: No Path to follow') return None path_x, path_y = self.path.pop(0) move_x = path_x - self.x move_y = path_y - self.y if move_y is -1 and move_x is 0: return 1 elif move_y is 1 and move_x is 0: return 2 elif move_y is 0 and move_x is -1: return 3 elif move_y is 0 and move_x is 1: return 4 else: print('%d, %d is invalid' % (move_x, move_y)) return None def make_move(self): # move = -1 # while move < 1 or move > 4: # move = int(input('Selection Direction: ')) # return move if self.path == []: self.target = self.find_nearest_unexplored() self.path = self.find_path_to_target((self.x, self.y), self.target) move = self.move_on_path() return move def run(self): running = True while self.find_all_unexplored() != []: # self.print_map() # Give input and receive response move = self.make_move() # print('Move: %d' % move) self.computer.set_input([move]) self.computer.execute_program() result = self.computer.get_last_value() # Find new position if move == 1: move_x = self.x move_y = self.y - 1 elif move == 2: move_x = self.x move_y = self.y + 1 elif move == 3: move_x = self.x - 1 move_y = self.y elif move == 4: move_x = self.x + 1 move_y = self.y # Update map bounds if move_x < self.min_x: self.min_x = move_x if move_x > self.max_x: self.max_x = move_x if move_y < self.min_y: self.min_y = move_y if move_y > self.max_y: self.max_y = move_y if result == 0: # Hit a wall if (move_x, move_y) not in self.map: self.map[(move_x, move_y)] = '#' elif result == 1: # Moved in direction if (move_x, move_y) not in self.map: self.map[(move_x, move_y)] = '.' self.x, self.y = move_x, move_y elif result == 2: # Found Oxygen System if (move_x, move_y) not in self.map: self.map[(move_x, move_y)] = 'O' self.x, self.y = move_x, move_y running = False else: print('Error: Invalid result %d' % result) running = False oxygen_distance = self.find_max_dist_from_oxygen() print(oxygen_distance)
class ArcadeCabinet: def __init__(self, file=None, echo=True): if file is None: self.computer = IntcodeComputer(echo=echo) else: self.computer = IntcodeComputer(file, echo=echo) self.width, self.height = 0, 0 self.grid = [] self.score = 0 self.paddle_x = -1 def run(self): running = True while running: self.computer.execute_program() self.read_output() self.print_grid() ball_pos = self.find_ball() paddle_pos = self.find_paddle() if ball_pos[0] < paddle_pos[0]: move = -1 elif ball_pos[0] == paddle_pos[0]: move = 0 elif ball_pos[0] > paddle_pos[0]: move = 1 self.move_paddle(move) running = not self.computer.finished def read_output(self): output = self.computer.get_output_values() for i in range(0, len(output), 3): x = output[i] y = output[i+1] tile = output[i+2] if x is -1 and y is 0: self.set_score(tile) else: self.set_tile(x, y, tile) def set_tile(self, x, y, tile): if not self.in_bounds(x, y): self.expand_grid(x+1, y+1) self.grid[x][y] = tile def set_score(self, score): self.score = score def in_bounds(self, x, y): if x >= self.width or y >= self.height: return False else: return True def expand_grid(self, new_width, new_height): if new_width > self.width: add_width = new_width - self.width for i in range(add_width): self.grid.append([0 for tile in range(self.height)]) self.width = new_width if new_height > self.height: add_height = new_height - self.height for column in self.grid: column.extend([0 for tile in range(add_height)]) self.height = new_height def print_grid(self): for y in range(self.height): for x in range(self.width): tile = self.grid[x][y] # print(tile, end='') if tile == 0: print(' ', end='') elif tile == 1: print('|', end='') elif tile == 2: print('#', end='') elif tile == 3: print('-', end='') elif tile == 4: print('*', end='') print('\n', end='') print('Score: %d' % self.score) def find_ball(self): for y in range(self.height): for x in range(self.width): tile = self.grid[x][y] if tile == 4: return (x, y) def find_paddle(self): for y in range(self.height): for x in range(self.width): tile = self.grid[x][y] if tile == 3: return (x, y) def move_paddle(self, move): self.computer.set_input([move]) def count_blocks(self): block_count = 0 for y in range(self.height): for x in range(self.width): tile = self.grid[x][y] if tile == 2: block_count += 1 return block_count