def fill_stats(self, game: Game): self.children_cnt = 1 self.wrapped_children_cnt = game.is_wrapped(self.pos) for c in self.children: cnt, wcnt = c.fill_stats(game) self.children_cnt += cnt self.wrapped_children_cnt += wcnt return self.children_cnt, self.wrapped_children_cnt
def recur(game: Game, depth=0, first_action=None): # process attempted new state at the beginning of the recursive call nonlocal nodes_evaluated, best_score, best_action nodes_evaluated += 1 bot = game.bot success = game.is_wrapped(target) delay_penalty = -2 # game.turn and distfield[bot.pos] essentially count the same thing and negate each other, # but: # - for searches terminated due to max_depth turn is irrelevant because it's the same, so # they automatically optimize for lower distfield # - for successfully terminated searches we ignore distfield and turn becomes relevant # - don't reward success beyond the naturally better score because of the above penalties # - only compare best scores for completed searchesso that the first point holds (otherwise # node score can be worse than that of its children) score = -game.remaining_unwrapped score += game.turn * delay_penalty if not success: score += distfield[bot.pos] * delay_penalty # hack: collect boosters we want to use booster = [b for b in game.game.boosters if b.pos == bot.pos] if booster: [booster] = booster if booster.code in 'B': score += 1000 success = True key = (bot.pos, bot.int_direction) if key in scores and scores[key] > score: return scores[key] = score if success or depth >= max_depth: if first_action and score > best_score: best_action = first_action best_score = score return for dp, action in Action.DIRS.items(): # never move backward, also means we never run into walls if distfield.get(bot.pos + dp, 99999) <= distfield[bot.pos]: recur(game.apply_action(action), depth + 1, first_action if first_action else action) recur(game.apply_action(Action.turnCW()), depth + 1, first_action if first_action else Action.turnCW()) recur(game.apply_action(Action.turnCCW()), depth + 1, first_action if first_action else Action.turnCCW())
def solve(task: Task, max_depth) -> Tuple[int, List[List[Action]], dict]: task = GridTask(task) game = Game(task) st_root = game.bots[0].pos spanning_tree = calculate_spanning_tree(game, st_root) target = None while not game.finished(): while game.inventory['B'] > 0: logger.info('attach extension') action = attach_lined(game) wrap_updates = game.apply_action(action) for p in wrap_updates: assert game.is_wrapped(p) spanning_tree[p].wrap() bot = game.bots[0] if target is None: target = spanning_tree[bot.pos].get_next_unwrapped().pos distfield = calculate_distance_field(game, target, bot.pos) #print_distfield(game, distfield) action = get_action(game, max_depth, distfield, target) assert action wrap_updates = game.apply_action(action) for p in wrap_updates: assert game.is_wrapped(p) spanning_tree[p].wrap() if game.is_wrapped(target): target = None score = game.finished() logger.info(game.inventory) extra = dict(final_manipulators=len(game.bots[0].manipulator)) return score, game.get_actions(), extra
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