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
示例#4
0
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