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
Example #2
0
    def solve(self, task: str) -> SolverResult:
        task = Task.parse(task)
        min_score = None
        min_actions = []
        min_extra = {}

        turnlist = [[]]
        if self.turns:
            turnlist += [[Action.turnCCW()],
                         [Action.turnCCW(), Action.turnCCW()],
                         [Action.turnCW()]]

        # turnlist = [[Action.turnCW()]]

        for turns in turnlist:
            game = Game(GridTask(task))
            for t in turns:
                game.apply_action(t)

            expected_score, actions, extra = solve(game, min_score)
            if expected_score is None:
                # solution has exceeded the best score and stopped
                continue
            if min_score is None or expected_score < min_score:
                min_score, min_actions, min_extra = expected_score, actions, extra
        return SolverResult(data=compose_actions(min_actions),
                            expected_score=min_score,
                            extra=min_extra)
Example #3
0
def run_for_errors(actions: List[Action]):
    task_data = Path(utils.project_root() / 'tasks' / 'part-0-mock' / 'prob-2003.desc').read_text()
    task = GridTask(Task.parse(task_data))
    game = Game(task)
    try:
        for a in actions:
            game.apply_action(a)
    except InvalidActionException:
        return
    else:
        assert False
    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 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 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 main():
    path = os.path.join(utils.get_data_dir(), 'qualifier/problem_4.json')
    with open(path) as fin:
        data = json.load(fin)
        m = re.match('.*/problem_(\\d+)\\.json', path)
        assert m
        data['problemId'] = int(m.group(1))

    game = Game(data, data['sourceSeeds'][0])
    ui = Gui(game, buttons=Gui.DEFAULT_BUTTONS_INTERACTIVE)
    
    while True:
        cmd = ui.wait_for_action()
        log.debug('{!r}'.format(cmd))
        if cmd is None:
            log.debug('done')
            break
        game.execute_char(CHARS_BY_COMMAND[cmd][0])
        ui.update(game)
Example #8
0
    def solve(self, task: str) -> SolverResult:
        task = Task.parse(task)
        min_score = None
        # min_actions = []
        # min_extra = {}

        turnlist = {
            'Eastborne': [],
            'Nordish': [Action.turnCCW()],
            'Westerling': [Action.turnCCW(),
                           Action.turnCCW()],
            'Southerner': [Action.turnCW()]
        }

        params = {}
        params['boostlist'] = 'B'
        if self.drill:
            params['boostlist'] += 'L'
        if self.teleport:
            params['boostlist'] += 'R'

        params['attach func'] = manip_configs[self.manipconf]

        for direction in turnlist:
            logger.info(f'{direction} started working')
            params['best score'] = min_score

            game = Game(GridTask(task))
            for t in turnlist[direction]:
                game.apply_action(t)

            expected_score, actions, extra = solve(game, params)
            logger.info(f'{direction} finished with {expected_score} score')
            if expected_score is None:
                # solution has exceeded the best score and stopped
                continue

            if min_score is None or expected_score < min_score:
                min_score, min_actions, min_extra = expected_score, actions, extra

        return SolverResult(data=compose_actions(min_actions),
                            expected_score=min_score,
                            extra=min_extra)
Example #9
0
def attach_lined(game: Game, extras: dict, botindex=0):
    bot = game.bots[botindex]
    d = None
    for d in Action.DIRS.keys():
        if d in bot.manipulator:
            break
    assert d is not None
    ccw = d.rotated_ccw()

    i = 0
    while True:
        candidate = d + ccw * i
        if candidate not in bot.manipulator:
            break
        candidate = d - ccw * i
        if candidate not in bot.manipulator:
            break
        i += 1

    game.apply_action(Action.attach(candidate.x, candidate.y))
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(task: Task, max_depth) -> Tuple[int, List[List[Action]], dict]:
    task = GridTask(task)

    game = Game(task)

    while not game.finished():
        while game.inventory['B'] > 0:
            logger.info('attach extension')
            game.apply_action(Action.attach(1, len(game.bots[0].manipulator) - 2))

        action = get_action(game, max_depth)
        game.apply_action(action)

    score = game.finished()
    logger.info(game.inventory)

    extra = dict(final_manipulators = len(game.bots[0].manipulator))

    return score, game.get_actions(), extra
Example #12
0
def attach_manip(game: Game, bot_area, botindex=0):
    bot = game.bots[botindex]
    d = None
    for d in Action.DIRS.keys():
        if d in bot.manipulator:
            break
    assert d is not None
    ccw = d.rotated_ccw()

    i = 0
    while True:
        candidate = d + ccw * i
        if candidate not in bot.manipulator:
            break
        candidate = d - ccw * i
        if candidate not in bot.manipulator:
            break
        i += 1

    for d in Action.DIRS.keys():
        if candidate + d not in bot_area:
            bot_area.append(candidate + d)
    game.apply_action(Action.attach(candidate.x, candidate.y))
Example #13
0
def main():
    s = Path(utils.project_root() / 'tasks' / 'part-1-initial' /
             'prob-145.desc').read_text()
    solver = BoostySolver([])
    t = time()
    sol = solver.solve(s)
    print(f'time elapsed: {time() - t:.4}')
    print(sol)
    task = Task.parse(s)
    score, sol, _ = solve(Game(GridTask(task)))
    print("score:", score)
    sol = compose_actions(sol)
    print(sol)
    print(len(sol), 'time units')
    sol_path = Path(utils.project_root() / 'outputs' / 'example-01-boosty.sol')
    sol_path.write_text(sol)
    print('result saved to', sol_path)
Example #14
0
def run_one_bot_game(actions: List[Action]):
    task_data = Path(utils.project_root() / 'tasks' / 'part-0-mock' / 'prob-2003.desc').read_text()
    task = GridTask(Task.parse(task_data))
    game = Game(task)
    for a in actions:
        game.apply_action(a)

    solution = compose_actions(game.get_actions())
    expected_score = game.finished()
    er = validate.run(task_data, solution)

    assert er.time is not None
    assert er.time == expected_score
Example #15
0
def run_cloned_game(actions: List[List[Action]]):
    task_data = Path(utils.project_root() / 'tasks' / 'part-0-mock' / 'prob-2003.desc').read_text()
    task = GridTask(Task.parse(task_data))
    game = Game(task)

    indices = [0] * len(actions)
    current = 0
    while not game.finished():
        if current == 0:
            botcount = len(game.bots)
        i = indices[current]
        game.apply_action(actions[current][i], current)
        indices[current] += 1
        current = (current + 1) % botcount

    solution = compose_actions(game.get_actions())
    expected_score = game.finished()
    er = validate.run(task_data, solution)

    assert er.time is not None
    assert er.time == expected_score
Example #16
0
    def draw_initial(self, game: Game):
        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])

        #borders
        #for some reason the left border is not shown
        for x in range(game.width + 2):
            char(Pt(x - 1, -1), 'H', FgColors.Dungeon)
            char(Pt(x - 1, game.height), 'H', FgColors.Dungeon)
        for y in range(game.height + 2):
            char(Pt(-1, y - 1), 'H', FgColors.Dungeon)
            char(Pt(game.width, y - 1), 'H', FgColors.Dungeon)

        for p, c in game.enumerate_grid():
            char(p, c, FgColors.Dungeon)
Example #17
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
Example #18
0
    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()
Example #19
0
def interactive(task_number):
    task_data = utils.get_problem_raw(task_number)
    use_db = task_number <= 999

    if use_db:
        conn = db.get_conn()
        cur = conn.cursor()
        cur.execute(
            '''
        SELECT id, data FROM tasks WHERE name = %s
        ''', [f'prob-{task_number:03d}'])
        [task_id, task_data_db] = cur.fetchone()
        task_data_db = zlib.decompress(task_data_db).decode()
        assert task_data_db == task_data

    task = GridTask(Task.parse(task_data))
    game = Game(task)
    score = None

    with contextlib.closing(Display(game)) as display:
        code, c = '', ''
        display.draw_initial(game)

        while not score:
            display.draw(game, f'lastchar = {code} {c!r}')

            code = display.stdscr.getch()

            action = None

            c = chr(code).upper()

            if c in '\x1B':
                break

            if c in Action.SIMPLE:
                action = Action.simple(c)

            # to perform complex action type it without spaces: B(1,-1)
            elif c in Action.PARAM:
                while c[-1] != ')':
                    code = display.stdscr.getch()
                    c = c + chr(code).upper()
                action = Action.parameterized(c)

            if display.current == 0:
                botcount = len(game.bots)
            if action:
                try:
                    game.apply_action(action, display.current)
                except InvalidActionException as exc:
                    display.draw_error(str(exc))
                else:
                    display.current = (display.current + 1) % botcount

            score = game.finished()

    if score is not None:
        print(f'Score: {score}')
        result = validate_replay(task_data, score, game.get_actions())
        print(result)
        if use_db:
            submit_replay(conn, task_id, result)
        else:
            mock_solutions = utils.project_root(
            ) / 'outputs' / 'mock_solutions'
            mock_solutions.mkdir(parents=True, exist_ok=True)
            with mock_solutions / f'prob-{task_number}.sol' as fin:
                fin.write_text(result.solution)
Example #20
0
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
Example #21
0
def test_wheel_timer():
    task_data = Path(utils.project_root() / 'tasks' / 'part-0-mock' / 'wheels.desc').read_text()
    task = GridTask(Task.parse(task_data))

    actionlist = ('QQDD' + 
                     'F' +
                     'ZZZZZZZZZZZZZZZZZZZZ' +
                     'F' +
                     'ZZZZZZZZZZZZZZZZZZZZ' + 
                     'ZZZZZZZZZ' +
                     'ZZZZZZZZZZZZZZZZZZZZ' +
                     'ZZZZZZZZZZZZZZZZZZZZ' +
                     'ZZZZZZZZZZ' + 
                     'D')

    game = Game(task)
    for a in actionlist:
        game.apply_action(Action.simple(a))

    solution = compose_actions(game.get_actions())
    expected_score = game.finished()
    assert expected_score is None

    game = Game(task)
    for a in actionlist:
        game.apply_action(Action.simple(a))
    game.apply_action(Action.WSAD('D'))

    solution = compose_actions(game.get_actions())
    expected_score = game.finished()
    er = validate.run(task_data, solution)

    assert er.time is not None
    assert er.time == expected_score
Example #22
0
def attach_squared(game: Game, extras: dict, botindex=0):
    bot = game.bots[botindex]
    d = None
    for d in Action.DIRS.keys():
        if d in bot.manipulator:
            break
    assert d is not None

    ccw = d.rotated_ccw()
    shoulder = extras['booster_count'] // 4

    candidate = None
    if candidate is None:
        i = 0
        while i <= shoulder / 2:
            candidate = d + ccw * i
            if candidate not in bot.manipulator:
                break
            candidate = d - ccw * i
            if candidate not in bot.manipulator:
                break
            i += 1
        else:
            candidate = None

    if candidate is None:
        left = d + ccw * (shoulder // 2)
        right = d - ccw * (shoulder // 2)
        i = 1
        while i < shoulder:
            candidate = left + d * i
            if candidate not in bot.manipulator:
                break
            candidate = right + d * i
            if candidate not in bot.manipulator:
                break
            i += 1
        else:
            candidate = None

    if candidate is None:
        left = d * shoulder + ccw * (shoulder // 2)
        right = d * shoulder - ccw * (shoulder // 2)
        i = 1
        while i < shoulder / 2:
            candidate = left - ccw * i
            if candidate not in bot.manipulator:
                break
            candidate = right + ccw * i
            if candidate not in bot.manipulator:
                break
            i += 1
        else:
            candidate = None

    if candidate is None:
        i = 1
        while d * (-i) in bot.manipulator:
            i += 1
        candidate = d * (-i)

    game.apply_action(Action.attach(candidate.x, candidate.y))
        c, b = it
        c = c.lower()
        cc = ord(c) - ord("n")
        # print(cc, b)
        print(c, cc % 6, COMMAND_BY_CHAR[c], b)


print_seq()
print()

json = {
    "width": 20,
    "height": 20,
    "filled": [],
    "sourceLength": 1,
    "units": [{"pivot": {"x": 0, "y": 1}, "members": [{"x": 0, "y": 0}]}],
}
marks = []
g = Game(json, 0)
ui = Gui(g)
for it in s.split():
    c, b = it
    print(it, COMMAND_BY_CHAR[c.lower()])
    if b == "1":
        marks.append(next(iter(g.get_current_figure_cells())))
    ui.update(g, marks)
    action = ui.wait_for_action()
    if action is None:
        break
    g.execute_char(c)
Example #24
0
    def solve(self, task: str) -> SolverResult:
        task = Task.parse(task)
        task = GridTask(task)
        game = Game(task)

        if not game.clone_spawn:
            return SolverResult(data=Pass(),
                                expected_score=None,
                                extra=dict(reason='no clone spawns'))
        if not game.inventory['C'] and not game.map_contains_booster('C'):
            return SolverResult(data=Pass(),
                                expected_score=None,
                                extra=dict(reason='no clone boosters'))

        cnt = 0
        while not game.finished():
            cnt += 1
            if cnt % 200 == 0:
                logging.info(
                    f'{len(game.bots)} bots; {game.remaining_unwrapped} unwrapped'
                )

            used_bots = [False for bot in game.bots]
            actions = [None for bot in game.bots]
            orig_bots = game.bots[:]

            if game.clone_spawn and game.inventory['C']:
                logging.info('need spawn')
                df = DistanceField(game.grid)
                df.build(game.clone_spawn)
                dist = df.dist

                best_rank = 1e10
                best_bot = None
                best_action = None
                for bot_index, bot in enumerate(orig_bots):
                    if dist[bot.pos] == 0:
                        continue
                    for d, a in Action.DIRS.items():
                        p = bot.pos + d
                        if not game.grid.in_bounds(p):
                            continue
                        rank = dist[p]
                        if rank < best_rank:
                            best_rank = rank
                            best_bot = bot_index
                            best_action = a
                #assert best_bot is not None
                #game.apply_action(best_action, best_bot)
                if best_bot is not None:
                    actions[best_bot] = best_action
                    used_bots[best_bot] = True

            boosters = [b.pos for b in game.boosters if b.code == 'C']
            if not game.finished() and game.clone_spawn and not game.inventory[
                    'C'] and boosters and not all(used_bots):
                df = DistanceField(game.grid)
                df.build(boosters)
                dist = df.dist

                best_rank = 1e10
                best_bot = None
                best_action = None
                for bot_index, bot in enumerate(orig_bots):
                    if used_bots[bot_index]:
                        continue
                    for d, a in Action.DIRS.items():
                        p = bot.pos + d
                        if not game.grid.in_bounds(p):
                            continue
                        rank = dist[p]
                        if rank < best_rank:
                            best_rank = rank
                            best_bot = bot_index
                            best_action = a
                assert best_bot is not None
                actions[best_bot] = best_action
                used_bots[best_bot] = True

            if game.finished():
                break

            df = DistanceField(game.grid)
            starts = list_unwrapped(game._wrapped)
            df.build(starts)
            dist = df.dist

            for bot_index, bot in enumerate(orig_bots):
                if game.finished():
                    break
                if used_bots[bot_index]:
                    game.apply_action(actions[bot_index], bot_index)
                    continue
                if game.inventory['C'] and bot.pos in game.clone_spawn:
                    game.apply_action(Action.clone(), bot_index)
                    logging.info('clone!!!')
                    continue
                if game.inventory['B'] > 0:
                    logger.info('attach extension')
                    game.apply_action(
                        Action.attach(1,
                                      len(game.bots[0].manipulator) - 2))
                    continue

                best_rank = 1e10
                best_action = None
                for d, a in Action.DIRS.items():
                    p = bot.pos + d
                    if not game.grid.in_bounds(p):
                        continue
                    rank = dist[p]
                    for j, bot2 in enumerate(orig_bots):
                        if j < bot_index:
                            d = bot.pos.manhattan_dist(bot2.pos)
                            rank += 10 * max(0, 30 - d)
                    if rank < best_rank:
                        best_rank = rank
                        best_action = a
                assert best_action is not None

                game.apply_action(best_action, bot_index)

        expected_score = score = game.finished()
        extra = dict(final_bots=len(game.bots))
        return SolverResult(data=compose_actions(game.get_actions()),
                            expected_score=expected_score,
                            extra=extra)
Example #25
0
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