Пример #1
0
    def __init__(self, state, actions, bounties, spawns, protection_memory):
        self.num_ships = len(actions.ships)

        # if there are no ships, there is nothing to do
        if self.num_ships == 0:
            return

        # read relevant spawning information
        self.spawns_wanted = spawns.ships_wanted
        self.spawns_possible = spawns.ships_possible
        likely_spawns = spawns.spawn_pos[0:self.spawns_possible]
        self.protected = np.setdiff1d(protection_memory, likely_spawns)

        # set up candidate moves for each ship and compute
        # distances on an appropriately weighted graph
        self.geometry(state, actions)

        # the optimal assignment will assign only one ship to each site
        # but we want more than one ship to go back to each yard so
        # we add duplicates of the yards to the rewards to make this possible
        duplicates = np.tile(state.my_yard_pos, self.num_ships - 1)
        ind_to_site = np.append(duplicates, state.sites)

        # calculate the value of going to a site for each ship
        cost_matrix = np.vstack(
            [self.rewards(ship, state, bounties) for ship in actions.ships])

        # find the optimal assignment of ships to destinations
        # the optimal assignment assigns ship_inds[i] to site_inds[i]
        ship_inds, site_inds = assignment(cost_matrix, maximize=True)

        # go through the solution of the optimal assignment problem and
        # order the moves by preference
        self.destinations = {}
        self.values = {}

        for ship_ind, site_ind in zip(ship_inds, site_inds):
            # store destination and value of the ship
            ship = actions.ships[ship_ind]
            self.destinations[ship] = ind_to_site[site_ind]
            self.values[ship] = cost_matrix[ship_ind, site_ind]

            # sort moves by how much they decrease the distance
            # to the assigned destination
            dest_dists = self.move_dists[ship][:, self.destinations[ship]]
            self.moves[ship] = self.moves[ship][dest_dists.argsort()]

        return
Пример #2
0
def move(state, actions, targets):
    # if there are no ships pending, there is nothing to do
    if len(actions.ships) == 0:
        return

    # calculate the value per step of going to a specific site
    cost_matrix, threat_matrix, threat_scores = matrices(
        state, actions, targets)

    # regularize infinities - replace them by very negative finite values
    # that can never be compensated by a good matching. so any matching
    # with an effective infinity is worse than any matching without one
    finite = np.isfinite(cost_matrix)
    infinite = ~finite
    eff_inf = 1 + 2 * len(actions.ships) * np.max(np.abs(cost_matrix[finite]))
    cost_matrix[infinite] = -eff_inf

    # find the optimal assignment of ships to sites
    ship_inds, sites = assignment(cost_matrix, maximize=True)

    # go through the solution - if the assigned site is legal and safe
    # we move onto it, otherwise we add the ship to list of ships
    # for which decisions are made independently
    threatened = []
    depositing = []

    for ship_ind, site in zip(ship_inds, sites):
        ship = actions.ships[ship_ind]
        pos, hal = state.my_ships[ship]

        # if the ship was assigned to an unsafe site, decide on a move later
        # unless the site is a protected yard
        if infinite[ship_ind, site] or threat_matrix[ship_ind, site]:
            threatened.append(ship_ind)
            continue

        # if the ship is depositing after the interest spike and
        # there is traffic at the yard, move freely
        spike = (state.total_steps - state.step) < STEPS_SPIKE
        spike = spike and (state.my_yard_pos.size > 0)
        if spike:
            yard_ind = np.argmin(state.dist[state.my_yard_pos, pos], axis=0)
            yard = state.my_yard_pos[yard_ind]
            close = state.dist[yard, pos] <= 3
            traffic = np.sum(state.dist[state.my_ship_pos, yard] <= 2) >= 6
            if traffic and close:
                depositing.append(ship_ind)
                continue

        decision = state.pos_to_move(pos, site)
        actions.decided[ship] = decision
        state.update(ship, decision)

    # decide on actions for ships that were assigned to unsafe sites
    for ship_ind in threatened:
        ship = actions.ships[ship_ind]
        pos, hal = state.my_ships[ship]

        # restrict to sites with fewest threats
        legal = np.flatnonzero(state.dist[pos, :] <= 1)
        scores = threat_scores[ship_ind, legal]
        candidates = legal[scores == scores.min()]

        # further restrict to sites with least opponent collisions
        scores = state.moved_this_turn[candidates]
        candidates = candidates[scores == scores.min()]

        # of these, choose the site with the highest ranking
        ranking = targets.moves[ship]
        ind = np.in1d(ranking, candidates).argmax()
        site = ranking[ind]
        decision = state.pos_to_move(pos, site)

        # if we don't have any safe squares to go to, and more cargo
        # than the cost to convert, convert and keep the difference
        if threat_matrix[ship_ind, site] and (hal >= state.convert_cost):
            decision = "CONVERT"

        actions.decided[ship] = decision
        state.update(ship, decision)

    for ship_ind in depositing:
        ship = actions.ships[ship_ind]
        pos, hal = state.my_ships[ship]

        # only check for threats, not self-collisions
        legal = np.flatnonzero(state.dist[pos, :] <= 1)
        scores = threat_scores[ship_ind, legal]
        candidates = legal[scores == scores.min()]

        ranking = targets.moves[ship]
        ind = np.in1d(ranking, candidates).argmax()
        site = ranking[ind]

        decision = state.pos_to_move(pos, site)
        actions.decided[ship] = decision
        state.update(ship, decision)

    actions.ships.clear()
    return
Пример #3
0
    def __init__(self, state, actions, bounties, spawns):
        self.num_ships = len(actions.ships)

        # если кораблей нет, делать нечего
        if self.num_ships == 0:
            return

        # защищаем те верфи, которые работают, и в этом ходу у них не будет спауна
        likely_spawns = spawns.spawn_pos[0:spawns.ships_possible]
        yards = np.setdiff1d(working_yards(state), likely_spawns)

        # расстояние от ближайшего корабля противника до каждой верфи
        inds = np.ix_(state.opp_ship_pos, yards)
        opp_ship_dist = np.amin(state.dist[inds],
                                axis=0,
                                initial=state.map_size)

        # расстояние ближайшего дружественного корабля к каждой верфи
        inds = np.ix_(state.my_ship_pos, yards)
        my_ship_dist = np.amin(state.dist[inds],
                               axis=0,
                               initial=state.map_size)

        # если корабли противника начинают приближаться к верфи по сравнению
        # к своим, возвращаемся, чтобы защитить их
        inds = opp_ship_dist <= (2 + my_ship_dist)
        self.protected = yards[inds]
        self.protection_radius = opp_ship_dist[inds]

        # настраиваем возможные ходы для каждого корабля и вычисляем
        # расстояния на правильно взвешенном графике
        self.geometry(state, actions)

        # оптимальное назначение присвоит каждому месту только один корабль
        # но мы хотим, чтобы на каждую верфь вернулось более одного корабля, поэтому
        # мы добавляем дубликаты верфей к наградам, чтобы это стало возможным
        duplicates = np.tile(state.my_yard_pos, self.num_ships - 1)
        ind_to_site = np.append(duplicates, state.sites)

        # рассчитываем стоимость посещения места для каждого корабля
        cost_matrix = np.vstack(
            [self.rewards(ship, state, bounties) for ship in actions.ships])

        # найти оптимальное назначение кораблей по направлениям
        # оптимальное назначение присваивает ship_inds [i] site_inds [i]
        ship_inds, site_inds = assignment(cost_matrix, maximize=True)

        # проходим решение задачи оптимального назначения и
        # упорядочиваем ходы по предпочтениям
        self.destinations = {}
        self.values = {}

        for ship_ind, site_ind in zip(ship_inds, site_inds):
            # сохранить пункт назначения и стоимость корабля
            ship = actions.ships[ship_ind]
            self.destinations[ship] = ind_to_site[site_ind]
            self.values[ship] = cost_matrix[ship_ind, site_ind]

            # sort перемещается по тому, насколько он уменьшает расстояние
            # в назначенный пункт назначения
            dest_dists = self.move_dists[ship][:, self.destinations[ship]]
            self.moves[ship] = self.moves[ship][dest_dists.argsort()]

        return
Пример #4
0
def move(state, actions, targets, protection_memory):
    # if there are no ships pending, there is nothing to do
    if len(actions.ships) == 0:
        return

    # calculate the value per step of going to a specific site
    cost_matrix, threats, weak_threats = matrices(state, actions, targets)

    # regularize infinities - replace them by very negative finite values
    # that can never be compensated by a good matching. so any matching
    # with an effective infinity is worse than any matching without one
    finite = np.isfinite(cost_matrix)
    infinite = ~finite
    eff_inf = 1 + 2 * len(actions.ships) * np.max(np.abs(cost_matrix[finite]))
    cost_matrix[infinite] = -eff_inf

    # find the optimal assignment of ships to sites
    ship_inds, sites = assignment(cost_matrix, maximize=True)

    # go through the solution - if the assigned site is legal and safe
    # we move onto it, otherwise we add the ship to list of ships
    # for which decisions are made independently
    threatened = []
    depositing = []

    for ship_ind, site in zip(ship_inds, sites):
        ship = actions.ships[ship_ind]
        pos, hal = state.my_ships[ship]

        # if the ship was assigned to an unsafe site, decide on a move later
        # unless the site is a protected yard
        if infinite[ship_ind, site] or threats[ship_ind, site]:
            if site not in protection_memory:
                threatened.append(ship_ind)
                continue

        # if the ship is depositing after the interest spike and
        # there is traffic at the yard, move freely
        spike = (state.total_steps - state.step) < STEPS_SPIKE
        spike = spike and (state.my_yard_pos.size > 0)
        if spike:
            yard_ind = np.argmin(state.dist[state.my_yard_pos, pos], axis=0)
            yard = state.my_yard_pos[yard_ind]
            close = state.dist[yard, pos] <= 3
            traffic = np.sum(state.dist[state.my_ship_pos, yard] <= 4) >= 10
            if traffic and close:
                depositing.append(ship_ind)
                continue

        decision = state.pos_to_move(pos, site)
        actions.decided[ship] = decision
        state.update(ship, decision)

    # decide on actions for ships that were assigned to unsafe sites
    for ship_ind in threatened:
        ship = actions.ships[ship_ind]
        pos, hal = state.my_ships[ship]

        illegal = (state.dist[pos, :] > 1)
        self_col = state.moved_this_turn
        weak_opp_col = weak_threats[ship_ind, :]

        # ideally, don't collide with opponents or our own ships
        opp_col_flag = False
        exclude = illegal | self_col | weak_opp_col

        # if this is impossible, don't collide with opponents
        if np.sum(~exclude) == 0:
            exclude = illegal | weak_opp_col

        # if this is impossible, don't collide with our own ships
        if np.sum(~exclude) == 0:
            opp_col_flag = True
            exclude = illegal | self_col

        # otherwise just make a move
        if np.sum(~exclude) == 0:
            exclude = illegal

        # in most of these situations, staying put is a bad move
        # we could get lucky escaping other ships
        if np.sum(~exclude) >= 2:
            exclude[pos] = True

        # get the highest-ranked moved that is not excluded
        candidates = state.sites[~exclude]
        ranking = targets.moves[ship]
        ind = np.in1d(ranking, candidates).argmax()
        site = ranking[ind]
        decision = state.pos_to_move(pos, site)

        # if we don't have any safe squares to go to, and more cargo
        # than it cost to convert, convert and keep the difference
        if opp_col_flag and (hal >= state.convert_cost):
            decision = "CONVERT"

        actions.decided[ship] = decision
        state.update(ship, decision)

    for ship_ind in depositing:
        ship = actions.ships[ship_ind]
        pos, hal = state.my_ships[ship]

        illegal = (state.dist[pos, :] > 1)
        weak_opp_col = weak_threats[ship_ind, :]

        # ideally don't collide with opponent ships
        exclude = illegal | weak_opp_col

        # otherwise just make a move
        if np.sum(~exclude) == 0:
            exclude = illegal

        # get the highest-ranked moved that is not excluded
        candidates = state.sites[~exclude]
        ranking = targets.moves[ship]
        ind = np.in1d(ranking, candidates).argmax()
        site = ranking[ind]

        decision = state.pos_to_move(pos, site)
        actions.decided[ship] = decision
        state.update(ship, decision)

    actions.ships.clear()
    return
Пример #5
0
    def __init__(self, state, actions, bounties, spawns):
        self.num_ships = len(actions.ships)

        # if there are no ships, there is nothing to do
        if self.num_ships == 0:
            return

        # protect those yards that are working and won't have a spawn this turn
        likely_spawns = spawns.spawn_pos[0:spawns.ships_possible]
        yards = np.setdiff1d(working_yards(state), likely_spawns)

        # distance of closest opponent ship to each yard
        inds = np.ix_(state.opp_ship_pos, yards)
        opp_ship_dist = np.amin(state.dist[inds],
                                axis=0,
                                initial=state.map_size)

        # distance of closest friendly ship to each yard
        inds = np.ix_(state.my_ship_pos, yards)
        my_ship_dist = np.amin(state.dist[inds],
                               axis=0,
                               initial=state.map_size)

        # if opponent ships start getting too close to a yard compared
        # to our own, start heading back to protect them
        inds = opp_ship_dist <= (2 + my_ship_dist)
        self.protected = yards[inds]
        self.protection_radius = opp_ship_dist[inds]

        # set up candidate moves for each ship and compute
        # distances on an appropriately weighted graph
        self.geometry(state, actions)

        # the optimal assignment will assign only one ship to each site
        # but we want more than one ship to go back to each yard so
        # we add duplicates of the yards to the rewards to make this possible
        duplicates = np.tile(state.my_yard_pos, self.num_ships - 1)
        ind_to_site = np.append(duplicates, state.sites)

        # calculate the value of going to a site for each ship
        cost_matrix = np.vstack(
            [self.rewards(ship, state, bounties) for ship in actions.ships])

        # find the optimal assignment of ships to destinations
        # the optimal assignment assigns ship_inds[i] to site_inds[i]
        ship_inds, site_inds = assignment(cost_matrix, maximize=True)

        # go through the solution of the optimal assignment problem and
        # order the moves by preference
        self.destinations = {}
        self.values = {}

        for ship_ind, site_ind in zip(ship_inds, site_inds):
            # store destination and value of the ship
            ship = actions.ships[ship_ind]
            self.destinations[ship] = ind_to_site[site_ind]
            self.values[ship] = cost_matrix[ship_ind, site_ind]

            # sort moves by how much they decrease the distance
            # to the assigned destination
            dest_dists = self.move_dists[ship][:, self.destinations[ship]]
            self.moves[ship] = self.moves[ship][dest_dists.argsort()]

        return
Пример #6
0
def move(state, actions, targets):
    # если нет ожидающих кораблей, то делать нечего
    if len(actions.ships) == 0:
        return

    # рассчитываем стоимость за каждый шаг, идя к определенному месту
    cost_matrix, threat_matrix, threat_scores = matrices(
        state, actions, targets)

    # упорядочим бесконечности - заменим их очень отрицательными конечными значениями
    # чтобы никогда не могло быть компенсировано хорошим соответствием. так что любое соответствие
    # с эффективной бесконечностью хуже, чем любое сопоставление без нее
    finite = np.isfinite(cost_matrix)
    infinite = ~finite
    eff_inf = 1 + 2 * len(actions.ships) * np.max(np.abs(cost_matrix[finite]))
    cost_matrix[infinite] = -eff_inf

    # находим оптимальное присваивание кораблей к местам
    ship_inds, sites = assignment(cost_matrix, maximize=True)

    # найти решение - если назначенное место законно и безопасно
    # переходим на него, иначе добавляем корабль в список кораблей
    # по которым решения принимаются независимо
    threatened = []
    depositing = []

    for ship_ind, site in zip(ship_inds, sites):
        ship = actions.ships[ship_ind]
        pos, hal = state.my_ships[ship]

        # если корабль был назначен на небезопасный объект, решаем переехать позже
        # если место не является охраняемой верфью
        if infinite[ship_ind, site] or threat_matrix[ship_ind, site]:
            threatened.append(ship_ind)
            continue

        # если корабль делает депозит после всплеска процентов и
        # в верфи движение, передвигаемся свободно
        spike = (state.total_steps - state.step) < STEPS_SPIKE
        spike = spike and (state.my_yard_pos.size > 0)
        if spike:
            yard_ind = np.argmin(state.dist[state.my_yard_pos, pos], axis=0)
            yard = state.my_yard_pos[yard_ind]
            close = state.dist[yard, pos] <= 3
            traffic = np.sum(state.dist[state.my_ship_pos, yard] <= 2) >= 6
            if traffic and close:
                depositing.append(ship_ind)
                continue

        decision = state.pos_to_move(pos, site)
        actions.decided[ship] = decision
        state.update(ship, decision)

    # принимаем решение о действиях для кораблей, которые были отнесены к небезопасным местам
    for ship_ind in threatened:
        ship = actions.ships[ship_ind]
        pos, hal = state.my_ships[ship]

        # ограничиваться местами с наименьшим количеством угроз
        legal = np.flatnonzero(state.dist[pos, :] <= 1)
        scores = threat_scores[ship_ind, legal]
        candidates = legal[scores == scores.min()]

        # далее ограничиваем места с наименьшим количеством столкновений с противниками
        scores = state.moved_this_turn[candidates]
        candidates = candidates[scores == scores.min()]

        # из них выбираем места с наивысшим рейтингом
        ranking = targets.moves[ship]
        ind = np.in1d(ranking, candidates).argmax()
        site = ranking[ind]
        decision = state.pos_to_move(pos, site)

        # если у нас нет безопасных площадок, куда можно было бы пойти, и еще груза
        # чем затраты на преобразование, преобразование и сохранение разницы
        if threat_matrix[ship_ind, site] and (hal >= state.convert_cost):
            decision = "CONVERT"

        actions.decided[ship] = decision
        state.update(ship, decision)

    for ship_ind in depositing:
        ship = actions.ships[ship_ind]
        pos, hal = state.my_ships[ship]

        # проверяем только на угрозы, а не на столкновения
        legal = np.flatnonzero(state.dist[pos, :] <= 1)
        scores = threat_scores[ship_ind, legal]
        candidates = legal[scores == scores.min()]

        ranking = targets.moves[ship]
        ind = np.in1d(ranking, candidates).argmax()
        site = ranking[ind]

        decision = state.pos_to_move(pos, site)
        actions.decided[ship] = decision
        state.update(ship, decision)

    actions.ships.clear()
    return