def calculate_distance_field(game: Game, source: Pt, target: Pt): # Calculate and return a distance field from the target, over visited cells only sentinel = object() front = deque([source, sentinel]) distfield = {source: 0} generation = 1 found = False while front: p = front.popleft() if p == sentinel: if found: break assert front generation += 1 front.append(sentinel) continue for d in Action.DIRS.keys(): p2 = p + d if (p2 not in distfield and game.in_bounds(p2) and game.is_passable(p2)): distfield[p2] = generation front.append(p2) if p2 == target: found = True return distfield
def calculate_spanning_tree(game: Game, pos: Pt): front = deque([pos]) visited = {pos: Treenode(pos, None)} found = None while front: p = front.popleft() pnode = visited[p] for d in Action.DIRS.keys(): p2 = p + d if (p2 not in visited and game.in_bounds(p2) and game.is_passable(p2)): visited[p2] = Treenode(p2, pnode) pnode.children.append(visited[p2]) front.append(p2) visited[pos].fill_stats(game) return visited
def solve(game: Game, params: dict) -> Tuple[Optional[int], List[List[Action]], dict]: cnt = 0 params['booster_count'] = sum(1 for b in game.boosters if b.code == 'B') map_center = Pt(game.grid.width // 2, game.grid.height // 2) teleport_list = [] while not game.finished(): cnt += 1 if cnt % 1000 == 0: logging.info(f'{game.remaining_unwrapped} unwrapped') bot = game.bots[0] extensions = { b.pos for b in game.boosters if b.code in params['boostlist'] } prev = {bot.pos: None} frontier = [bot.pos] # searching target depth = 0 while frontier: best_rank = 0 dst = None for p in frontier: rank = 0 if p in extensions: rank += 5 for m in bot.manipulator: q = p + m if (game.in_bounds(q) and game.grid[q] == '.' and not game.is_wrapped(q) and visible(game.grid, q, p)): rank += 1 if rank > best_rank: best_rank = rank dst = p if dst is not None: break new_frontier = [] if depth == 0 and 'R' in params['boostlist']: new_frontier = teleport_list[:] for p in new_frontier: prev[p] = bot.pos for p in frontier: for d in Action.DIRS.keys(): p2 = p + d if (p2 not in prev and game.in_bounds(p2) and (game.grid[p2] == '.' or bot.drill_timer - depth > 0)): prev[p2] = p new_frontier.append(p2) frontier = new_frontier depth += 1 assert dst is not None assert dst != bot.pos # teleport if 'R' in params['boostlist'] and game.inventory['R'] > 0: if map_center.manhattan_dist( bot.pos) < map_center.manhattan_dist(dst): game.apply_action(Action.reset()) logger.info('reset teleport') teleport_list.append(bot.pos) # gathering path path = [] p = dst while p != bot.pos: d = p - prev[p] if d not in Action.DIRS.keys(): assert 'R' in params['boostlist'] and p in teleport_list path.append(Action.teleport(p.x, p.y)) logger.info('teleport away') else: path.append(Action.DIRS[d]) p = prev[p] assert p is not None path.reverse() assert depth == len(path), (depth, len(path)) for a in path: game.apply_action(a) if params['best score'] is not None and game.turn >= params[ 'best score']: return None, [], {} # boosters if game.inventory['B'] > 0: logger.info('attach extension') params['attach func'](game, params, 0) if 'L' in params['boostlist'] and game.inventory['L'] > 0: logger.info('use drill') game.apply_action(Action.drill()) score = game.finished() logger.info(game.inventory) extra = dict(final_manipulators=len(game.bots[0].manipulator)) return score, game.get_actions(), extra
def solve(task: Task, turns: str, bestscore=None) -> Tuple[Optional[int], List[List[Action]], dict]: task = GridTask(task) game = Game(task) cnt = 0 for t in turns: game.apply_action(Action.simple(t)) while not game.finished(): cnt += 1 if cnt % 1000 == 0: logging.info(f'{game.remaining_unwrapped} unwrapped') extensions = {b.pos for b in game.boosters if b.code == 'B'} prev = {game.bots[0].pos: None} frontier = [game.bots[0].pos] while frontier: best_rank = 0 dst = None for p in frontier: rank = 0 if p in extensions: rank += 5 rank += len( manipulators_will_wrap(game.grid, game._wrapped, p, game.bots[0].manipulator)) if rank > best_rank: best_rank = rank dst = p if dst is not None: break new_frontier = [] for p in frontier: for d in Action.DIRS.keys(): p2 = p + d if (p2 not in prev and game.in_bounds(p2) and game.grid[p2] == '.'): prev[p2] = p new_frontier.append(p2) frontier = new_frontier assert dst is not None assert dst != game.bots[0].pos path = [] p = dst while p != game.bots[0].pos: d = p - prev[p] path.append(Action.DIRS[d]) p = prev[p] assert p is not None path.reverse() for a in path: game.apply_action(a) if bestscore is not None and game.turn >= bestscore: return None, [], {} if game.inventory['B'] > 0: logger.info('attach extension') attach_to = Pt(1, len(game.bots[0].manipulator) - 2) for t in turns: attach_to = turn_pt(attach_to, t) game.apply_action(Action.attach(attach_to.x, attach_to.y)) score = game.finished() logger.info(game.inventory) extra = dict(final_manipulators=len(game.bots[0].manipulator)) return score, game.get_actions(), extra
def draw(self, game: Game, extra_status=''): stdscr, pad = self.stdscr, self.pad def char(p, char, fgcolor): offset = Pt(1, 1) if game.in_bounds(p) and game.is_wrapped(p): bg_color = curses.COLOR_BLUE else: bg_color = curses.COLOR_BLACK p = p + offset pad.addstr(self.height - p.y + 1, p.x * 2, char + ' ', colormapping[fgcolor, bg_color]) bot = game.bots[(self.current - 1) % len(game.bots)] area = max( bot.pos.manhattan_dist(bot.pos + m) for m in bot.manipulator) for y in range(bot.pos.y - area, bot.pos.y + area + 1): for x in range(bot.pos.x - area, bot.pos.x + area + 1): p = Pt(x, y) if not game.in_bounds(p): continue char(p, game.grid[p], FgColors.Dungeon) for b in game.boosters: char(b.pos, b.code, FgColors.Booster) for t in game.teleport_spots: char(t, '+', FgColors.Spot) for c in game.clone_spawn: char(c, 'X', FgColors.Spot) for b in game.bots: for m in bot.manipulator: w = b.pos + m if game.in_bounds(w) and geom.visible(game.grid, b.pos, w): char(m, '*', FgColors.Manipulator) for b in game.bots: char(b.pos, '@', FgColors.InactivePlayer) char(game.bots[self.current].pos, '@', FgColors.Player) offset = self.screen_offset(game.size(), bot.pos) pad.refresh(offset.y, offset.x, 0, 0, curses.LINES - 2, curses.COLS - 1) if self.last_error: status_line = self.last_error.ljust(curses.COLS)[:curses.COLS - 1] self.last_error = '' stdscr.addstr( curses.LINES - 1, 0, status_line, colormapping[curses.COLOR_YELLOW | BRIGHT, curses.COLOR_RED]) else: status_line = f'turn={game.turn} ' + \ f'pos=({bot.pos.x}, {bot.pos.y}) ' + \ f'unwrapped={game.remaining_unwrapped} ' status_line += ' '.join(f'{b}={game.inventory[b]}' for b in Booster.PICKABLE) if game.bots[self.current].wheels_timer: status_line += f' WHEELS({game.bots[self.current].wheels_timer})' if game.bots[self.current].drill_timer: status_line += f' DRILL({game.bots[self.current].drill_timer})' if extra_status: status_line += ' ' status_line += extra_status # LMAO: "It looks like simply writing the last character of a window is impossible with curses, for historical reasons." status_line = status_line.ljust(curses.COLS)[:curses.COLS - 1] stdscr.addstr( curses.LINES - 1, 0, status_line, colormapping[curses.COLOR_YELLOW | BRIGHT, curses.COLOR_BLUE]) stdscr.refresh()
def solve(task: Task) -> Tuple[int, List[List[Action]], dict]: task = GridTask(task) game = Game(task) cnt = 0 while not game.finished(): cnt += 1 if cnt % 1000 == 0: logging.info(f'{game.remaining_unwrapped} unwrapped') prev = {game.bots[0].pos: None} frontier = [game.bots[0].pos] while frontier: best_rank = 0 dst = None for p in frontier: rank = len( manipulators_will_wrap(game.grid, game._wrapped, p, game.bots[0].manipulator)) if rank > best_rank: best_rank = rank dst = p if dst is not None: break new_frontier = [] for p in frontier: for d in Action.DIRS.keys(): p2 = p + d if (p2 not in prev and game.in_bounds(p2) and game.grid[p2] == '.'): prev[p2] = p new_frontier.append(p2) frontier = new_frontier assert dst is not None assert dst != game.bots[0].pos path = [] p = dst while p != game.bots[0].pos: d = p - prev[p] path.append(Action.DIRS[d]) p = prev[p] assert p is not None path.reverse() for a in path: game.apply_action(a) if game.inventory['B'] > 0: logger.info('attach extension') game.apply_action( Action.attach(1, len(game.bots[0].manipulator) - 2)) score = game.finished() logger.info(game.inventory) extra = dict(final_manipulators=len(game.bots[0].manipulator)) return score, game.get_actions(), extra