예제 #1
0
    def get_entities_in_front(self, entity):
        """
        Get the entities that are in front of the given entity.

        :param entity: The entity for which we should get the entities that are in front of it
        """
        pos = Position(entity.get_position())
        pos.add(entity.get_move_delta())
        return self.get_entities_at(pos)
예제 #2
0
    def get_entities_in_front(self, entity):
        """
        Get the entities that are in front of the given entity.

        :param entity: The entity for which we should get the entities that are in front of it
        """
        pos = Position(entity.get_position())
        pos.add(entity.get_move_delta())
        return self.get_entities_at(pos)
예제 #3
0
 def can_step(self, agent):
     position = Position(agent.get_position())
     position.add(agent.get_move_delta(1))
     return not self.entity_rect_collision(
         (
             position.get_x(), 
             position.get_y(), 
             agent.get_width(), 
             agent.get_height()
         )
     )
예제 #4
0
def assert_input():
    b = Board()
    b.put(Position(4, 3), Soldier(player_1))
    b.put(Position(4, 2), Soldier(player_1))
    b.put(Position(4, 4), Soldier(player_2))
    b.put(Position(4, 5), Soldier(player_2))
    g = Game(b)
    g.replenish(100)

    player_action = g.validate_player_move(PlayerMove.from_literal(player_2, "4443 4546"))
    assert(str(player_action) == '55->54(ATK),56->57(MOV)')
    player_action = g.validate_player_move(PlayerMove.from_literal(player_1, "4342 4252"))
    assert(str(player_action) == '54->53(DEF),53->63(UPG)')
예제 #5
0
def assert_invalid_input():
    b = Board()

    b.put(Position(4, 3), Soldier(player_1))
    b.put(Position(4, 4), Soldier(player_2))

    g = Game(b)
    g.replenish(100)

    try:
        g.validate_player_move(PlayerMove.from_literal(player_2, "5554 5565"))
    except rule.InvalidMoveException:
        pass
    else:
        assert (None)
예제 #6
0
def assert_attack_defend():
    b = Board()
    p2u1 = Position.from_literal('55')
    p2u2 = Position.from_literal('66')
    p2u3 = Position.from_literal('61')
    #p2u4 = Position.from_literal('65')

    p1u1 = Position.from_literal('54')
    p1u2 = Position.from_literal('53')
    p1u3 = Position.from_literal('62')
    p1u4 = Position.from_literal('67')
    p1u5 = Position.from_literal('56')

    b.put(p2u1, Soldier(player_2))
    b.put(p2u2, Rider(player_2, flip_skillset=True))
    b.put(p2u3, Soldier(player_2))
    #b.put(p2u4, Barbarian(player_2, flip_skillset=True)))

    b.put(p1u1, Rider(player_1))
    b.put(p1u2, Soldier(player_1))
    b.put(p1u3, Rider(player_1))
    b.put(p1u4, Soldier(player_1))
    b.put(p1u5, Soldier(player_1))

    g = Game(b)
    g.replenish(100)

    # renderer.show_canvas(
    #     paint.get_painted_canvas(
    #         g, {player_1:'a', player_2:'b'}, player_1))

    g = g.make_move([
        PlayerMove.from_literal(player_2, "5554 6654 6162"),
        PlayerMove.from_literal(player_1, "5354 6254 6766 5655 5446")
    ])

    # for clash_brief in g.round_brief.clash_briefs:
    #     print(clash_brief.brief())

    # for battle_brief in g.round_brief.battle_briefs:
    #     print(battle_brief.brief())

    assert (g.board.at(p2u1).owner == player_1)
    assert (g.board.at(p2u2).owner == player_1)
    assert (g.board.at(p2u3) is None)

    assert (g.board.at(p1u1) is None)
    assert (g.board.at(p1u2).owner == player_1)
    assert (g.board.at(p1u3).owner == player_2)
    assert (g.board.at(p1u4) is None)
    assert (g.board.at(p1u5) is None)

    assert (g.board.at(Position.from_literal('46')).owner == player_1)
예제 #7
0
def assert_clash():
    b = Board()
    p1p = Position(4, 3)
    p2p = Position(4, 4)
    b.put(p1p, Soldier(player_1))
    b.put(p2p, Soldier(player_2))
    g = Game(b)
    g.replenish(100)

    g = g.make_move([
        PlayerMove.from_literal(player_2, "5554"),
        PlayerMove.from_literal(player_1, "5455")
    ])

    assert (g.board.at(p1p) is None)
    assert (g.board.at(p2p) is None)
예제 #8
0
파일: board.py 프로젝트: cottyard/Lancer
def set_out(board):
    for row, setting, player in [
        (0, board_setting_1st_row, player_2),
        (1, board_setting_2nd_row, player_2),
        (board_size_y - 1, board_setting_1st_row, player_1),
        (board_size_y - 2, board_setting_2nd_row, player_1)
    ]:
        for i in range(board_size_x):
            board.put(Position(i, row), setting[i](player))
예제 #9
0
파일: board.py 프로젝트: cottyard/Lancer
 def deserialize(cls, payload):
     b = Board()
     s = json.loads(payload)
     for i in range(board_size_x):
         for j in range(board_size_y):
             u = s.pop(0)
             if u != 0:
                 b.put(Position(i, j), Unit.deserialize(u))
     return b
예제 #10
0
파일: board.py 프로젝트: cottyard/Lancer
 def serialize(self):
     s = []
     for i in range(board_size_x):
         for j in range(board_size_y):
             unit = self.at(Position(i, j))
             if unit:
                 s.append(unit.serialize())
             else:
                 s.append(0)
     return json.dumps(s)
예제 #11
0
def assert_move_conflict():
    b = Board()
    p1p1 = Position(4, 2)
    p2p1 = Position(4, 4)

    p1p2 = Position(5, 2)
    p1p3 = Position(6, 1)
    p2p2 = Position(5, 4)

    b.put(p1p1, Soldier(player_1))
    b.put(p2p1, Soldier(player_2))
    b.put(p1p2, Soldier(player_1))
    b.put(p1p3, Rider(player_1))
    b.put(p2p2, Soldier(player_2))
    g = Game(b)
    g.replenish(100)

    g = g.make_move([
        PlayerMove.from_literal(player_2, "5554 6564"),
        PlayerMove.from_literal(player_1, "5354 6364 7264")
    ])

    assert (g.board.at(p1p1) is None)
    assert (g.board.at(p2p1) is None)
    assert (g.board.at(p1p2) is None)
    assert (g.board.at(p1p3) is not None)
    assert (g.board.at(p2p2) is None)
    assert (g.board.at(Position(5, 3)).owner == player_1)
예제 #12
0
def center(pos, cent, w, h):
    """
    Given a position in-game, returns the corresponding position when padded to 128 by 128, around cent, the center.
    """
    if (pos.x - cent.x) % w < (cent.x - pos.x) % w:
        x_adj = 64 + (pos.x - cent.x) % w
    else:
        x_adj = 64 - (cent.x - pos.x) % w
    if (pos.y - cent.y) % h < (cent.y - pos.y) % h:
        y_adj = 64 + (pos.y - cent.y) % h
    else:
        y_adj = 64 - (cent.y - pos.y) % h
    return Position(x_adj, y_adj)
예제 #13
0
def assert_clash():
    b = Board()
    p1p = Position(4, 3)
    p1p2 = Position(5, 6)
    p2p = Position(4, 4)
    s = Spearman(player_1, SkillSet())
    s.endow(Skill(PositionDelta(0, 1)))
    b.put(p1p, s)
    r = Rider(player_1)
    r.endow(Skill(PositionDelta(-1, -2)))
    b.put(p1p2, r)
    b.put(p2p, Soldier(player_2))
    g = Game(b)
    g.replenish(100)

    g = g.make_move([
        PlayerMove.from_literal(player_2, "4443"),
        PlayerMove.from_literal(player_1, "5644 4344")])

    assert(type(g.martyr_list[0].board_unit.unit) == Soldier)
    assert(type(g.board.at(p1p)) == Spearman)
    assert(type(g.board.at(p2p)) == Rider)
예제 #14
0
def assert_buffs():
    b = Board()

    b.put(Position.from_literal('55'), make_perfect(Lancer(player_1, SkillSet())))
    b.put(Position.from_literal('66'), make_perfect(Knight(player_1, SkillSet())))
    b.put(Position.from_literal('46'), make_perfect(Knight(player_1, SkillSet())))
    b.put(Position.from_literal('68'), make_perfect(Warrior(player_2, SkillSet())))
    b.put(Position.from_literal('78'), make_perfect(Spearman(player_1, SkillSet())))
    b.put(Position.from_literal('88'), make_perfect(Spearman(player_1, SkillSet())))
    b.put(Position.from_literal('53'), make_perfect(Soldier(player_1)))
    b.put(Position.from_literal('52'), make_perfect(Soldier(player_2)))
    b.put(Position.from_literal('59'), Swordsman(player_1, SkillSet()))

    g = Game(b)
    g = g.make_move([
        PlayerMove.from_literal(player_1, "4241 4442 5563 4857 6757 7757"),
        PlayerMove.from_literal(player_2, "")])

    assert(g.supply[player_1] == 29) # 40 - 16 + 5
예제 #15
0
    def get_free_positions(self):
        """
        Get all positions without any entities
        :return: A list of positions without entities.
        """

        free = []

        for x in range(self.width):
            for y in range(self.height):
                p = Position((x, y))
                if len(self.get_entities_at(p)) == 0:
                    free.append(p)

        return free
예제 #16
0
def assert_attack_defend():
    b = Board()
    p2u1 = Position.from_literal('55')
    p2u2 = Position.from_literal('66')
    p2u3 = Position.from_literal('61')

    p1u1 = Position.from_literal('54')
    p1u2 = Position.from_literal('53')
    p1u3 = Position.from_literal('62')
    p1u4 = Position.from_literal('67')
    p1u5 = Position.from_literal('56')

    b.put(p2u1, Soldier(player_2))
    b.put(p2u2, make_perfect(Rider(player_2)))
    b.put(p2u3, Soldier(player_2))

    b.put(p1u1, make_perfect(Rider(player_1)))
    b.put(p1u2, Soldier(player_1))
    b.put(p1u3, make_perfect(Rider(player_1)))
    b.put(p1u4, Soldier(player_1))
    b.put(p1u5, Soldier(player_1))

    g = Game(b)
    g.replenish(100)

    g = g.make_move([
        PlayerMove.from_literal(player_2, "4443 5543 5051"),
        PlayerMove.from_literal(player_1, "4243 5143 5655 4544 4335")])

    assert(g.board.at(p2u1).owner == player_1)
    assert(g.board.at(p2u2).owner == player_1)
    assert(g.board.at(p2u3) is None)

    assert(g.board.at(p1u1) is None)
    assert(g.board.at(p1u2).owner == player_1)
    assert(g.board.at(p1u3).owner == player_2)
    assert(g.board.at(p1u4) is None)
    assert(g.board.at(p1u5) is None)

    assert(g.board.at(Position.from_literal('46')).owner == player_1)
예제 #17
0
파일: game.py 프로젝트: cottyard/Lancer
    def get_random_player_move(self, player):
        move_list = []
        while random.randint(0, 12) != 0:
            if random.randint(0, 8) == 0:
                recruit_position = Position(
                    random.randint(0, board_size_x - 1),
                    rule.spawn_row[player])
                move = Move(recruit_position, recruit_position)
            else:
                move = random.choice(
                    rule.all_valid_moves(self.board, player, True))
            try:
                self.validate_player_move(
                    PlayerMove(player, move_list + [move]))
                move_list.append(move)
            except rule.InvalidMoveException:
                break

        print(move_list)
        return PlayerMove(player, move_list)
예제 #18
0
def assert_recall():
    b = Board()

    b.put(Position.from_literal('55'), King(player_1))
    b.put(Position.from_literal('57'), make_perfect(Soldier(player_2, SkillSet())))

    b.put(Position.from_literal('88'), make_perfect(Soldier(player_2, SkillSet())))
    b.put(Position.from_literal('89'), make_perfect(Lancer(player_1, SkillSet())))

    b.put(Position.from_literal('11'), make_perfect(Lancer(player_1, SkillSet())))
    
    g = Game(b)
    try:
        g = g.make_move([
            PlayerMove.from_literal(player_1, "5478"),
            PlayerMove.from_literal(player_2, "")])
    except:
        pass
    else:
        raise Exception()

    try:
        g = g.make_move([
            PlayerMove.from_literal(player_1, "4500"),
            PlayerMove.from_literal(player_2, "")])
    except:
        pass
    else:
        raise Exception()

    g = g.make_move([
        PlayerMove.from_literal(player_1, "5400"),
        PlayerMove.from_literal(player_2, "")])
    
    assert(g.board.at(Position.from_literal('11')) is None)
    assert(g.board.at(Position.from_literal('65')).owner == player_1)
예제 #19
0
    def step(self, game):
        def dist(a, b):
            return min(abs(a.x - b.x), game.size - abs(a.x - b.x)) + min(abs(a.y - b.y), game.size - abs(a.y - b.y))
        commands = {}
        next_pos = {}  # ship id: next position
        next_ships = []  # next_ships[y][x] = list of ships that will end want to move to y x
        rem = game.max_turns - game.turn
        for y in range(game.size):
            next_ships.append([])
            for x in range(game.size):
                next_ships[y].append([])

        self.halite = game.banks[self.id]
        for ship in game.ships.values():
            if ship.owner_id == self.id:
                if ship.halite > 800 or game.turn + dist(ship, self.shipyard) + 20 > game.max_turns:
                    self.returning[ship.id] = True
                elif ship.x == self.shipyard.x and ship.y == self.shipyard.y:
                    self.returning[ship.id] = False
                if ship.halite < game.cells[ship.y][ship.x][0] // 10:
                    next_pos[ship.id] = Position(ship.x, ship.y)
                else:
                    if random.random() < self.eps:
                        t = Position(random.randint(0, game.size), random.randint(0, game.size))
                    elif self.returning[ship.id]:
                        t = Position(self.shipyard.x, self.shipyard.y)
                    else:
                        t = Position(ship.x, ship.y)
                        for dx in range(-2, 3):
                            for dy in range(-2, 3):
                                p = Position((ship.x + dx) % game.size, (ship.y + dy) % game.size)
                                if (game.cells[p.y][p.x][0]) / (dist(ship, p) + 1) > game.cells[t.y][t.x][0] / (dist(t, ship) + 1):
                                    t = p
                    xdl = (ship.x - t.x) % game.size
                    xdr = (t.x - ship.x) % game.size
                    ydd = (ship.y - t.y) % game.size
                    ydu = (t.y - ship.y) % game.size

                    if xdl == xdr == 0:
                        x_dir = 0
                    elif xdl <= xdr:
                        x_dir = -1
                    else:
                        x_dir = 1

                    if ydd == ydu == 0:
                        y_dir = 0
                    elif ydd <= ydu:
                        y_dir = -1
                    else:
                        y_dir = 1

                    if x_dir != 0 and y_dir != 0:
                        x_pen = game.cells[ship.y][(ship.x + x_dir) % game.size][0]
                        y_pen = game.cells[(ship.y + y_dir) % game.size][ship.x][0]
                        if len(next_ships[ship.y][(ship.x + x_dir) % game.size]) > 0:
                            x_pen += 3000
                        elif game.cells[ship.y][(ship.x + x_dir) % game.size][2] != -1:
                            x_pen += 300
                        if len(next_ships[(ship.y + y_dir) % game.size][ship.x]) > 0:
                            y_pen += 3000
                        elif game.cells[(ship.y + y_dir) % game.size][ship.x][2] != -1:
                            y_pen += 300
                        if x_pen < y_pen:
                            next_pos[ship.id] = Position((ship.x + x_dir) % game.size, ship.y)
                            if x_dir == -1:
                                commands[ship.id] = MoveCommand(self.id, ship.id, 'W')
                            else:
                                commands[ship.id] = MoveCommand(self.id, ship.id, 'E')
                        else:
                            next_pos[ship.id] = Position(ship.x, (ship.y + y_dir) % game.size)
                            if y_dir == -1:
                                commands[ship.id] = MoveCommand(self.id, ship.id, 'S')
                            else:
                                commands[ship.id] = MoveCommand(self.id, ship.id, 'N')
                    elif x_dir != 0:
                        next_pos[ship.id] = Position((ship.x + x_dir) % game.size, ship.y)
                        if x_dir == -1:
                            commands[ship.id] = MoveCommand(self.id, ship.id, 'W')
                        else:
                            commands[ship.id] = MoveCommand(self.id, ship.id, 'E')
                    elif y_dir != 0:
                        next_pos[ship.id] = Position(ship.x, (ship.y + y_dir) % game.size)
                        if y_dir == -1:
                            commands[ship.id] = MoveCommand(self.id, ship.id, 'S')
                        else:
                            commands[ship.id] = MoveCommand(self.id, ship.id, 'N')
                    else:
                        next_pos[ship.id] = Position(ship.x, ship.y)
                next_ships[next_pos[ship.id].y][next_pos[ship.id].x].append(ship)

        q = [ship for ship in game.ships.values() if ship.owner_id == self.id and ship.id in next_pos and (next_pos[ship.id].x != ship.x or next_pos[ship.id].y != ship.y)]
        while q:
            ship = q.pop()
            nx = next_pos[ship.id].x
            ny = next_pos[ship.id].y
            if len(next_ships[ny][nx]) > 1 and not (rem <= 50 and nx == self.shipyard.x and ny == self.shipyard.y):
                cur = Position(ship.x, ship.y)
                done = False
                visited = set()
                while not done:
                    cur = next_pos[game.cells[cur.y][cur.x][2]]
                    # if hits empty or enemy, then not a cycle
                    if game.cells[cur.y][cur.x][2] == -1 or game.ships[game.cells[cur.y][cur.x][2]].owner_id != self.id:
                        break
                    # if ship stops, then not a cycle
                    if cur == next_pos[game.cells[cur.y][cur.x][2]]:
                        break
                    if cur == Position(ship.x, ship.y):
                        done = True
                        continue
                    elif game.cells[cur.y][cur.x][2] in visited:
                        break
                    visited.add(game.cells[cur.y][cur.x][2])
                else:
                    continue
                next_ships[next_pos[ship.id].y][next_pos[ship.id].x].remove(ship)
                next_pos[ship.id].x = ship.x
                next_pos[ship.id].y = ship.y
                commands[ship.id] = MoveCommand(self.id, ship.id, 'O')
                q.extend(next_ships[ship.y][ship.x])
                next_ships[ship.y][ship.x].append(ship)

        ret = list(commands.values())
        if (len(next_ships[self.shipyard.y][self.shipyard.x]) == 0 and self.halite >= 1000 and rem > 100
                and np.sum(game.cells[:, :, 0]) * 3 > self.map_starting_halite):
            ret.append(SpawnShipCommand(self.id, None))
        return ret
예제 #20
0
파일: board.py 프로젝트: cottyard/Lancer
 def iterate_units(self, func):
     for i in range(board_size_x):
         for j in range(board_size_y):
             u = self.board[i][j]
             if u is not None:
                 func(u, Position(i, j))
예제 #21
0
파일: board.py 프로젝트: cottyard/Lancer
 def iterate(self, func):
     for i in range(board_size_x):
         for j in range(board_size_y):
             p = Position(i, j)
             func(self.board.at(p), p)
예제 #22
0
파일: board.py 프로젝트: cottyard/Lancer
 def iterate_battles(self, func):
     for i in range(board_size_x):
         for j in range(board_size_y):
             p = Position(i, j)
             if self.arrive_board.at(p).count() > 0:
                 func(p)
예제 #23
0
    def step(self, game):
        def dist(a, b):
            return min(abs(a.x - b.x), game.width - abs(a.x - b.x)) + min(
                abs(a.y - b.y), game.height - abs(a.y - b.y))

        commands = {}
        next_pos = {}  # ship id: next position
        next_ships = [
        ]  # next_ships[y][x] = list of ships that will end want to move to y x
        for y in range(game.height):
            next_ships.append([])
            for x in range(game.width):
                next_ships[y].append([])

        for dropoff in self.new_dropoffs:
            self.dropoffs.append(
                game.constructs[game.cells[dropoff.y][dropoff.x][1]])

        # attraction = np.zeros((game.height, game.width))
        dominance = np.zeros((game.height, game.width), dtype=int)
        mined = np.zeros((game.height, game.width), dtype=bool)
        for x in range(game.width):
            for y in range(game.height):
                for dx in range(-5, 6):
                    for dy in range(-5 + abs(dx), 6 - abs(dx)):
                        wx = (x + dx) % game.width
                        wy = (y + dy) % game.height
                        if game.cells[wy][wx][2] != -1:
                            if game.ships[game.cells[wy][wx]
                                          [2]].owner_id == self.id:
                                dominance[y][x] += 1
                            else:
                                dominance[y][x] -= 1
                        # attraction[y][x] += game.cells[wy][wx][0] / (2 ** (abs(dx) + abs(dy)))

        self.halite = game.bank[self.id]
        if game.max_turns - game.turn > 200:
            for x in range(game.width):
                for y in range(game.height):
                    for dropoff in self.dropoffs:
                        if abs(x - dropoff.x) + abs(y - dropoff.y) < 25:
                            break
                    else:
                        if game.cells[y][x][1] != -1 or dominance[y][
                                x] < 5 or game.max_turns - game.turn <= 100:
                            continue
                        surrounding_halite = 0
                        for dx in range(-10, 11):
                            for dy in range(-10 + abs(dx), 11 - abs(dx)):
                                surrounding_halite += game.cells[
                                    (y + dy) % game.height][(x + dx) %
                                                            game.width][0]
                        if surrounding_halite > 2000:
                            self.pd = Position(x, y)

        dropoff_ship_id = None
        if self.pd is not None:
            mine = [s for s in game.ships.values() if s.owner_id == self.id]
            rich = [
                s for s in game.ships.values()
                if s.owner_id == self.id and s.halite + self.halite +
                game.cells[self.pd.y][self.pd.x][0] >= 4000
            ]

            if len(mine) > 0:
                cm = min(mine, key=lambda s: dist(s, self.pd))
                dropoff_ship_id = cm.id
                if len(rich) > 0:
                    cr = min(rich, key=lambda s: dist(s, self.pd))
                    if dist(cr, self.pd) - 3 < dist(cm, self.pd):
                        dropoff_ship_id = cr.id

        for ship in sorted(game.ships.values(), key=lambda s: s.id):
            if ship.owner_id != self.id:
                continue

            if dropoff_ship_id is not None and ship.id == dropoff_ship_id:
                if ship.x != self.pd.x or ship.y != self.pd.y:
                    t = self.pd
                    # print(f'Ship {dropoff_ship_id} targeting {t} for dropoff construction')
                elif self.halite + game.cells[self.pd.y][self.pd.x][
                        0] + game.ships[dropoff_ship_id].halite >= 4000:
                    commands[ship.id] = ConstructDropoffCommand(
                        self.id, ship.id)
                    self.pd = None
                    self.halite -= 4000
                    self.new_dropoffs.append(Position(ship.x, ship.y))
                    continue
                else:
                    # print(f'Ship {dropoff_ship_id} waiting for dropoff construction halite')
                    next_pos[ship.id] = Position(ship.x, ship.y)
                    continue
            else:
                nd = min(self.dropoffs,
                         key=lambda d: dist(ship, d))  # nearest dropoff

                if ship.halite > 950 or game.turn + dist(
                        ship, nd) + 20 > game.max_turns:
                    self.returning[ship.id] = True
                elif ship.halite == 0:
                    self.returning[ship.id] = False
                if ship.halite < game.cells[ship.y][ship.x][0] // 10:
                    next_pos[ship.id] = Position(ship.x, ship.y)
                    next_ships[next_pos[ship.id].y][next_pos[
                        ship.id].x].append(ship)
                    continue
                if self.returning[ship.id]:
                    t = Position(nd.x, nd.y)
                    # print(f'Ship {ship.id} targeting {t} for a return')
                else:
                    # local mining
                    t = Position(ship.x, ship.y)
                    for dx in range(-3, 4):
                        for dy in range(-3 + abs(dx), 4 - abs(dx)):
                            wx = (ship.x + dx) % game.width
                            wy = (ship.y + dy) % game.height
                            if not mined[wy][wx] and game.cells[wy][wx][
                                    0] - 50 * (abs(dx) + abs(dy) + dist(
                                        Position(wx, wy), nd)) > game.cells[
                                            t.y][t.x][0] - 50 * (
                                                dist(t, ship) + dist(t, nd)):
                                t.x = wx
                                t.y = wy

                    # long distance mining
                    if game.cells[t.y][t.x][0] - 50 * (dist(t, ship) + dist(
                            t, nd) - dist(ship, nd)) <= 100:
                        v = game.cells[t.y][t.x][0] / (dist(t, ship) +
                                                       dist(t, nd) + 1)
                        for dx in range(-10, 11):
                            for dy in range(-10 + abs(dx), 11 - abs(dx)):
                                pos = Position((ship.x + dx) % game.width,
                                               (ship.y + dy) % game.height)
                                pnd = min(self.dropoffs,
                                          key=lambda d: dist(pos, d))
                                if not mined[pos.y][pos.x] and game.cells[
                                        pos.y][pos.x][0] / (dist(pos, ship) +
                                                            dist(pos, pnd) +
                                                            1) > v:
                                    t = pos
                                    v = game.cells[pos.y][pos.x][0] / (
                                        abs(dx) + abs(dy) + dist(pos, pnd) + 1)
                        # print(f'Ship {ship.id} targeting {t} for long distance mining')
                    else:
                        pass
                        # print(f'Ship {ship.id} targeting {t} for local mining')
                    mined[t.y][t.x] = True

            xdl = (ship.x - t.x) % game.width
            xdr = (t.x - ship.x) % game.width
            ydd = (ship.y - t.y) % game.height
            ydu = (t.y - ship.y) % game.height

            if xdl == xdr == 0:
                x_dir = 0
            elif xdl <= xdr:
                x_dir = -1
            else:
                x_dir = 1

            if ydd == ydu == 0:
                y_dir = 0
            elif ydd <= ydu:
                y_dir = -1
            else:
                y_dir = 1

            if x_dir != 0 and y_dir != 0:
                x_pen = game.cells[ship.y][(ship.x + x_dir) % game.width][0]
                y_pen = game.cells[(ship.y + y_dir) % game.height][ship.x][0]
                if len(next_ships[ship.y][(ship.x + x_dir) % game.width]) > 0:
                    x_pen += 3000
                elif game.cells[ship.y][(ship.x + x_dir) %
                                        game.width][2] != -1:
                    x_pen += 300
                if len(next_ships[ship.y + y_dir][ship.x]) > 0:
                    y_pen += 3000
                elif game.cells[(ship.y + y_dir) %
                                game.height][ship.x][2] != -1:
                    y_pen += 300
                if x_pen < y_pen:
                    next_pos[ship.id] = Position((ship.x + x_dir) % game.width,
                                                 ship.y)
                    if x_dir == -1:
                        commands[ship.id] = MoveCommand(self.id, ship.id, 'W')
                    else:
                        commands[ship.id] = MoveCommand(self.id, ship.id, 'E')
                else:
                    next_pos[ship.id] = Position(ship.x, (ship.y + y_dir) %
                                                 game.height)
                    if y_dir == -1:
                        commands[ship.id] = MoveCommand(self.id, ship.id, 'S')
                    else:
                        commands[ship.id] = MoveCommand(self.id, ship.id, 'N')
            elif x_dir != 0:
                next_pos[ship.id] = Position((ship.x + x_dir) % game.width,
                                             ship.y)
                if x_dir == -1:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'W')
                else:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'E')
            elif y_dir != 0:
                next_pos[ship.id] = Position(ship.x,
                                             (ship.y + y_dir) % game.height)
                if y_dir == -1:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'S')
                else:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'N')
            else:
                next_pos[ship.id] = Position(ship.x, ship.y)
            next_ships[next_pos[ship.id].y][next_pos[ship.id].x].append(ship)

        # print(next_pos)
        # print(game.ships)
        # print(next_ships)
        q = [
            ship for ship in game.ships.values()
            if ship.owner_id == self.id and ship.id in next_pos and (
                next_pos[ship.id].x != ship.x or next_pos[ship.id].y != ship.y)
        ]
        while q:
            ship = q.pop()
            nx = next_pos[ship.id].x
            ny = next_pos[ship.id].y
            if len(next_ships[ny][nx]) > 1 and not (
                    game.max_turns - game.turn <= 50
                    and any(d.x == nx and d.y == ny for d in self.dropoffs)):
                # is ship part of cycle, let the cycle do its thing no matter what
                current = next_pos[ship.id]
                while current != Position(ship.x, ship.y):
                    if game.cells[next_pos[ship.id].y][next_pos[
                            ship.id].x][2] == -1 or game.ships[game.cells[
                                next_pos[ship.id].y][next_pos[
                                    ship.id].x][2]].owner_id != self.id:
                        break
                    if current == next_pos[game.cells[next_pos[ship.id].y][
                            next_pos[ship.id].x][2]]:
                        break
                    current = next_pos[game.cells[next_pos[ship.id].y][
                        next_pos[ship.id].x][2]]
                else:
                    continue

                # print(f'Stopped ship id {ship.id} to prevent collision')
                next_ships[next_pos[ship.id].y][next_pos[ship.id].x].remove(
                    ship)
                next_pos[ship.id].x = ship.x
                next_pos[ship.id].y = ship.y
                commands[ship.id] = MoveCommand(self.id, ship.id, 'O')
                q.extend(next_ships[ship.y][ship.x])
                next_ships[ship.y][ship.x].append(ship)

        ret = list(commands.values())
        if (len(next_ships[self.shipyard.y][self.shipyard.x]) == 0
                and self.halite >= (1000 if self.pd is None else 5000)
                and game.max_turns - game.turn > 100):
            ret.append(SpawnShipCommand(self.id, None))
        return ret
예제 #24
0
    def build_position(self, ticker):
        global positions, highest, lowest
        try:
            last = float(ticker['last'])
            amount = int(position_unit * 2 * last)
            # 建仓
            if len(positions) == 0 and last >= highest:
                ret = futureAPI.take_order('', self.instrument_id, 1, last,
                                           amount, 1, 20)
                if ret and ret['result']:
                    new_order_id = ret['order_id']
                    print('建多仓:挂单开多,order_id: %s' % new_order_id)
                    time.sleep(WAIT_DEAL)
                    info = futureAPI.get_order_info(new_order_id,
                                                    self.instrument_id)
                    print('建仓订单信息: %s' % info)
                    status = info['status']
                    if status == '2':
                        deal_price = float(info['price_avg'])
                        filled_qty = int(info['filled_qty'])
                        coin_amount = float(filled_qty * 10 / deal_price)
                        stop_loss = deal_price - 0.5 * N
                        position = Position(price=deal_price,
                                            amount=coin_amount,
                                            stop_loss=stop_loss,
                                            time=timestamp2string(time.time()),
                                            side='more')
                        positions.append(position)
                    else:
                        futureAPI.revoke_order(self.instrument_id,
                                               new_order_id)

            if len(positions) == 0 and last <= lowest:
                ret = futureAPI.take_order('', self.instrument_id, 2, last,
                                           amount, 1, 20)
                if ret and ret['result']:
                    new_order_id = ret['order_id']
                    print('建空仓:挂单开空,order_id: %s' % new_order_id)
                    time.sleep(WAIT_DEAL)
                    info = futureAPI.get_order_info(new_order_id,
                                                    self.instrument_id)
                    print('订单信息: %s' % info)
                    status = info['status']
                    if status == '2':
                        deal_price = float(info['price_avg'])
                        filled_qty = int(info['filled_qty'])
                        coin_amount = float(filled_qty * 10 / deal_price)
                        stop_loss = deal_price + 0.5 * N
                        position = Position(price=deal_price,
                                            amount=coin_amount,
                                            stop_loss=stop_loss,
                                            time=timestamp2string(time.time()),
                                            side='less')
                        positions.append(position)
                    else:
                        futureAPI.revoke_order(self.instrument_id,
                                               new_order_id)

            highest = max(highest, last)
            lowest = min(lowest, last)

        except Exception as e:
            print('建仓出错, %s' % repr(e))
            traceback.print_exc()
예제 #25
0
    def add_position(self, ticker):
        global positions, N
        try:
            # 加仓&止损
            if len(positions) > 0:
                last = float(ticker['last'])
                print('当前仓位: %d, 仓位信息:' % len(positions))
                for i in range(len(positions)):
                    cur = positions[i]
                    if cur.side == 'more':
                        profit = (last - cur.price) / cur.price * 100
                    else:
                        profit = (cur.price - last) / cur.price * 100
                    print(
                        '第%d个仓位: 委托价: %.3f, 数量: %.2f, 方向: %s, 止损价: %.3f, 买入时间: %s, 当前盈利: %.2f%%'
                        % (i + 1, cur.price, cur.amount, cur.side,
                           cur.stop_loss, cur.time, profit))
                prev_position = positions[-1]
                last_buy_price = prev_position.price
                side = prev_position.side
                amount = int(position_unit * 2 * last)
                last_stop_loss_price = prev_position.stop_loss

                if side == 'more':
                    if last - last_buy_price >= 0.5 * N:
                        ret = futureAPI.take_order('', self.instrument_id, 1,
                                                   last, amount, 1, 20)
                        if ret and ret['result']:
                            new_order_id = ret['order_id']
                            print('多仓加仓,order_id: %s' % new_order_id)
                            time.sleep(WAIT_DEAL)
                            info = futureAPI.get_order_info(
                                new_order_id, self.instrument_id)
                            print('订单信息: %s' % info)
                            status = info['status']
                            if status == '2':
                                deal_price = float(info['price_avg'])
                                filled_qty = int(info['filled_qty'])
                                coin_amount = float(filled_qty * 10 /
                                                    deal_price)
                                stop_loss = deal_price - 0.5 * N
                                position = Position(price=deal_price,
                                                    amount=coin_amount,
                                                    stop_loss=stop_loss,
                                                    time=timestamp2string(
                                                        time.time()),
                                                    side='more')
                                positions.append(position)
                            else:
                                futureAPI.revoke_order(self.instrument_id,
                                                       new_order_id)

                    elif last <= last_stop_loss_price or last <= lowest:
                        sell_more_batch(futureAPI, self.instrument_id, last)
                        thread.start_new_thread(ensure_sell_more, (
                            futureAPI,
                            self.coin_name,
                            self.instrument_id,
                            last,
                            last_buy_price,
                        ))
                        positions = []
                if side == 'less':
                    if last < last_buy_price - 0.5 * N:
                        ret = futureAPI.take_order('', self.instrument_id, 2,
                                                   last, amount, 1, 20)
                        if ret and ret['result']:
                            new_order_id = ret['order_id']
                            print('空仓加仓,order_id: %s' % new_order_id)
                            time.sleep(WAIT_DEAL)
                            info = futureAPI.get_order_info(
                                new_order_id, self.instrument_id)
                            print('订单信息: %s' % info)
                            status = info['status']
                            if status == '2':
                                deal_price = float(info['price_avg'])
                                filled_qty = int(info['filled_qty'])
                                coin_amount = float(filled_qty * 10 /
                                                    deal_price)
                                stop_loss = deal_price + 0.5 * N
                                position = Position(price=deal_price,
                                                    amount=coin_amount,
                                                    stop_loss=stop_loss,
                                                    time=timestamp2string(
                                                        time.time()),
                                                    side='less')
                                positions.append(position)
                            else:
                                futureAPI.revoke_order(self.instrument_id,
                                                       new_order_id)

                    elif last >= last_stop_loss_price or last >= highest:
                        sell_less_batch(futureAPI, self.instrument_id, last)
                        thread.start_new_thread(ensure_sell_less, (
                            futureAPI,
                            self.coin_name,
                            self.instrument_id,
                            last,
                            last_buy_price,
                        ))
                        positions = []
        except Exception as e:
            print('加仓出错:%s' % repr(e))
            traceback.print_exc()
예제 #26
0
    def generate_start(self):
        """
        Sets self to a standard initial game state, generating a map using perlin noise. 
        """
        for i, player in enumerate(self.players):
            player.id = i

        self.max_turns = round(self.size * 3.125) + 300

        self.banks = {player.id: 5000 for player in self.players}

        if len(self.players) == 2:
            perlin = np.square(
                _generate_perlin_noise_2d((self.size, self.size // 2), (4, 2)))
            noise = np.clip(
                np.random.normal(1, 0.5, size=(self.size, self.size // 2)),
                0.5, 10)
            max_halite = np.amax(perlin * noise)
            actual_max = random.randint(800, 1000)
            left_half = np.clip(perlin * noise * (actual_max / max_halite), 0,
                                1000).astype(int)
        else:
            perlin = np.square(
                _generate_perlin_noise_2d((self.size // 2, self.size // 2),
                                          (2, 2)))
            noise = np.clip(
                np.random.normal(1, 0.5,
                                 size=(self.size // 2, self.size // 2)), 0.5,
                10)
            max_halite = np.amax(perlin * noise)
            actual_max = random.randint(800, 1000)
            upper_left = np.clip(perlin * noise * (actual_max / max_halite), 0,
                                 1000).astype(int)
            left_half = np.concatenate((upper_left, np.flip(upper_left, 0)), 0)
        hlt = np.concatenate((left_half, np.flip(left_half, 1)), 1)

        if len(self.players) == 2:
            self.constructs[0] = Shipyard(self.players[0].id, 0, self.size / 4,
                                          self.size / 2)
            self.shipyard_pos[self.players[0].id] = Position(
                self.size / 4, self.size / 2)
            self.constructs[1] = Shipyard(self.players[1].id, 1,
                                          self.size * 3 / 4 - 1, self.size / 2)
            self.shipyard_pos[self.players[1].id] = Position(
                self.size * 3 / 4 - 1, self.size / 2)
        else:
            self.constructs[0] = Shipyard(self.players[0].id, 0, self.size / 4,
                                          self.size / 4)
            self.shipyard_pos[self.players[0].id] = Position(
                self.size / 4, self.size / 4)
            self.constructs[1] = Shipyard(self.players[1].id, 1,
                                          self.size * 3 / 4 - 1, self.size / 4)
            self.shipyard_pos[self.players[1].id] = Position(
                self.size * 3 / 4 - 1, self.size / 4)
            self.constructs[2] = Shipyard(self.players[2].id, 2, self.size / 4,
                                          self.size * 3 / 4 - 1)
            self.shipyard_pos[self.players[2].id] = Position(
                self.size / 4, self.size * 3 / 4 - 1)
            self.constructs[3] = Shipyard(self.players[3].id, 3,
                                          self.size * 3 / 4 - 1,
                                          self.size * 3 / 4 - 1)
            self.shipyard_pos[self.players[3].id] = Position(
                self.size * 3 / 4 - 1, self.size * 3 / 4 - 1)

        self.cells = np.zeros(shape=(self.size, self.size, 4), dtype=int)
        self.cells[:, :, 0] = hlt
        self.cells[:, :, 1:3] = -1
        for shipyard in self.constructs.values():
            self.cells[shipyard.y][shipyard.x][0] = 0
            self.cells[shipyard.y][shipyard.x][1] = shipyard.id
예제 #27
0
 def can_step(self, agent):
     position = Position(agent.get_position())
     position.add(agent.get_move_delta(1))
     return not self.entity_rect_collision(
         (position.get_x(), position.get_y(), agent.get_width(),
          agent.get_height()))
예제 #28
0
    def step(self, game):
        frame = game.cells.copy()
        no_ship = frame[:, :, 2] == -1
        for ship in game.ships.values():
            frame[:, :, 2][frame[:, :, 2] == ship.id] = (1 if ship.owner_id
                                                         == self.id else -1)
        frame[:, :, 2][no_ship] = 0
        frame = pad_frame(frame, game.shipyard_pos[self.id])
        frame = np.divide(frame, (1000, 1, 1, 1000))
        meta = (game.width, game.max_turns - game.turn, game.bank[self.id],
                max(game.bank[p.id] for p in game.players if p.id != self.id))
        meta = np.divide(meta, (64, 500, 10000, 10000))

        if self.memory is not None:
            if self.prev_frame is not None:
                ship_hlt_delta = sum(
                    s.halite for s in game.ships.values()
                    if s.owner_id == self.id) - self.prev_ship_halite
                bank_hlt_delta = game.bank[self.id] - self.halite
                ship_delta = (len(
                    [s
                     for s in game.ships.values() if s.owner_id == self.id]) -
                              self.prev_ships)
                reward = R_HLT_SHIP * ship_hlt_delta + R_HLT_BANK * bank_hlt_delta + R_SHIP * ship_delta
                self.memory.add_sample(self.prev_frame, self.prev_meta,
                                       self.prev_action, reward, False, frame,
                                       meta)
            if game.turn + 1 == game.max_turns:
                reward = R_WIN if meta[2] > meta[3] else R_LOSE
                self.memory.add_sample(frame, meta, self.prev_action, reward,
                                       True, None, None)
            if self.memory.num_samples >= min(320, self.memory.size / 10):
                self.total_loss += train(self.network, self.memory)

        self.prev_action = np.zeros((128, 128), dtype=int)
        self.prev_ship_halite = sum(s.halite for s in game.ships.values()
                                    if s.owner_id == self.id)
        self.prev_ships = len(
            [s for s in game.ships.values() if s.owner_id == self.id])
        self.prev_frame = frame.copy()
        self.prev_meta = meta.copy()

        moves = self.network.predict([
            np.array(frame).reshape((1, 128, 128, 4)),
            np.array(meta).reshape(1, -1)
        ])[0]

        self.halite = game.bank[self.id]

        commands = {}
        next_pos = {}
        next_ships = [
        ]  # next_ships[y][x] = list of ships that will end want to move to y x
        rem = game.max_turns - game.turn
        for y in range(game.height):
            next_ships.append([])
            for x in range(game.width):
                next_ships[y].append([])

        for x in range(game.width):
            for y in range(game.height):
                p = center(Position(x, y), self.shipyard, game.width,
                           game.height)
                if game.cells[y][x][2] == -1 or game.ships[
                        game.cells[y][x][2]].owner_id != self.id:
                    continue
                move = np.argmax(moves[p.y][p.x]) if random.random() < (
                    1 - self.eps) else random.randint(0, 5)
                self.prev_action[x][y] = move
                ship = game.ships[game.cells[y][x][2]]
                if move == 0:
                    if self.override_collisions:
                        next_pos[ship.id] = Position(x, y)
                elif game.cells[y][x][3] < game.cells[y][x][0] // 10:
                    if self.verbose == 1:
                        print(
                            f'{game.ships[game.cells[y][x][2]]} attempted to move without sufficient halite'
                        )
                    if self.override_collisions:
                        next_pos[ship.id] = Position(x, y)
                elif move == 1:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'N')
                    if self.override_collisions:
                        next_pos[ship.id] = Position(x, (y + 1) % game.height)
                elif move == 2:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'E')
                    if self.override_collisions:
                        next_pos[ship.id] = Position((x + 1) % game.width, y)
                elif move == 3:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'S')
                    if self.override_collisions:
                        next_pos[ship.id] = Position(x, (y - 1) % game.height)
                elif move == 4:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'W')
                    if self.override_collisions:
                        next_pos[ship.id] = Position((x - 1) % game.width, y)
                elif move == 5:
                    if self.halite + game.cells[y][x][0] + game.cells[y][x][
                            3] >= 4000 and game.cells[y][x][1] == -1:
                        commands[ship.id] = ConstructDropoffCommand(
                            self.id, ship.id)
                    elif self.override_collisions:
                        next_pos[ship.id] = Position(x, y)
                if self.override_collisions:
                    next_ships[next_pos[ship.id].y][next_pos[
                        ship.id].x].append(ship)
        if self.override_collisions:
            q = [
                ship for ship in game.ships.values()
                if ship.owner_id == self.id and (next_pos[
                    ship.id].x != ship.x or next_pos[ship.id].y != ship.y)
            ]
            while q:
                ship = q.pop()
                nx = next_pos[ship.id].x
                ny = next_pos[ship.id].y
                if len(next_ships[ny][nx]) > 1 and not (
                        rem <= 50 and nx == self.shipyard.x
                        and ny == self.shipyard.y):
                    p = Position(ship.x, ship.y)
                    done = False
                    visited = set()
                    while not done:
                        p = next_pos[game.cells[p.y][p.x][2]]
                        # if hits empty or enemy, then not a cycle
                        if game.cells[p.y][p.x][2] == -1 or game.ships[
                                game.cells[p.y][p.x][2]].owner_id != self.id:
                            break
                        # if ship stops, then not a cycle
                        if p == next_pos[game.cells[p.y][p.x][2]]:
                            break
                        if p == Position(ship.x, ship.y):
                            done = True
                            continue
                        elif game.cells[p.y][p.x][2] in visited:
                            break
                        visited.add(game.cells[p.y][p.x][2])
                    else:
                        continue
                    if self.verbose == 1:
                        print(f'Overrode collision for {ship}')
                    next_ships[next_pos[ship.id].y][next_pos[
                        ship.id].x].remove(ship)
                    next_pos[ship.id].x = ship.x
                    next_pos[ship.id].y = ship.y
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'O')
                    q.extend(next_ships[ship.y][ship.x])
                    next_ships[ship.y][ship.x].append(ship)

        ret = list(commands.values())
        if (len(next_ships[self.shipyard.y][self.shipyard.x]) == 0
                and self.halite >= 1000 and rem > 100 and
                np.sum(game.cells[:, :, 0]) * 3 > self.map_starting_halite):
            ret.append(SpawnShipCommand(self.id, None))
        return ret
    def step(self, game):
        frame = game.cells.copy()
        no_ship = frame[:, :, 2] == -1
        for ship in game.ships.values():
            frame[:, :, 2][frame[:, :, 2] == ship.id] = (1 if ship.owner_id
                                                         == self.id else -1)
        frame[:, :, 2][no_ship] = 0
        frame = pad_frame(frame, game.shipyard_pos[self.id])
        frame = np.divide(frame, (1000, 1, 1, 1000))
        meta = (game.width, game.max_turns - game.turn, game.bank[self.id],
                max(game.bank[p.id] for p in game.players if p.id != self.id))
        meta = np.divide(meta, (64, 500, 10000, 10000))

        moves = self.model.predict([
            np.array(frame).reshape((1, 128, 128, 4)),
            np.array(meta).reshape(1, -1)
        ])[0]

        self.halite = game.bank[self.id]

        commands = {}
        next_pos = {}
        next_ships = [
        ]  # next_ships[y][x] = list of ships that will end want to move to y x
        rem = game.max_turns - game.turn
        for y in range(game.height):
            next_ships.append([])
            for x in range(game.width):
                next_ships[y].append([])

        for x in range(game.width):
            for y in range(game.height):
                p = center(Position(x, y), self.shipyard, game.width,
                           game.height)
                if game.cells[y][x][2] == -1 or game.ships[
                        game.cells[y][x][2]].owner_id != self.id:
                    continue
                move = np.argmax(moves[p.y][p.x])
                ship = game.ships[game.cells[y][x][2]]
                if move == 0:
                    if self.override_collisions:
                        next_pos[ship.id] = Position(x, y)
                elif game.cells[y][x][3] < game.cells[y][x][0] // 10:
                    if self.verbose == 1:
                        print(
                            f'{game.ships[game.cells[y][x][2]]} attempted to move without sufficient halite'
                        )
                    if self.override_collisions:
                        next_pos[ship.id] = Position(x, y)
                elif move == 1:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'N')
                    if self.override_collisions:
                        next_pos[ship.id] = Position(x, (y + 1) % game.height)
                elif move == 2:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'E')
                    if self.override_collisions:
                        next_pos[ship.id] = Position((x + 1) % game.width, y)
                elif move == 3:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'S')
                    if self.override_collisions:
                        next_pos[ship.id] = Position(x, (y - 1) % game.height)
                elif move == 4:
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'W')
                    if self.override_collisions:
                        next_pos[ship.id] = Position((x - 1) % game.width, y)
                elif move == 5:
                    if self.halite + game.cells[y][x][0] + game.cells[y][x][
                            3] >= 4000:
                        commands[ship.id] = ConstructDropoffCommand(
                            self.id, ship.id)
                    elif self.override_collisions:
                        next_pos[ship.id] = Position(x, y)
                if self.override_collisions:
                    next_ships[next_pos[ship.id].y][next_pos[
                        ship.id].x].append(ship)
        if self.override_collisions:
            q = [
                ship for ship in game.ships.values()
                if ship.owner_id == self.id and (next_pos[
                    ship.id].x != ship.x or next_pos[ship.id].y != ship.y)
            ]
            while q:
                ship = q.pop()
                nx = next_pos[ship.id].x
                ny = next_pos[ship.id].y
                if len(next_ships[ny][nx]) > 1 and not (
                        rem <= 50 and nx == self.shipyard.x
                        and ny == self.shipyard.y):
                    cur = Position(ship.x, ship.y)
                    done = False
                    visited = set()
                    while not done:
                        cur = next_pos[game.cells[cur.y][cur.x][2]]
                        # if hits empty or enemy, then not a cycle
                        if game.cells[cur.y][
                                cur.x][2] == -1 or game.ships[game.cells[
                                    cur.y][cur.x][2]].owner_id != self.id:
                            break
                        # if ship stops, then not a cycle
                        if cur == next_pos[game.cells[cur.y][cur.x][2]]:
                            break
                        if cur == Position(ship.x, ship.y):
                            done = True
                            continue
                        elif game.cells[cur.y][cur.x][2] in visited:
                            break
                        visited.add(game.cells[cur.y][cur.x][2])
                    else:
                        continue
                    if self.verbose == 1:
                        print(f'Overrode collision for {ship}')
                    next_ships[next_pos[ship.id].y][next_pos[
                        ship.id].x].remove(ship)
                    next_pos[ship.id].x = ship.x
                    next_pos[ship.id].y = ship.y
                    commands[ship.id] = MoveCommand(self.id, ship.id, 'O')
                    q.extend(next_ships[ship.y][ship.x])
                    next_ships[ship.y][ship.x].append(ship)

        ret = list(commands.values())
        if (len(next_ships[self.shipyard.y][self.shipyard.x]) == 0
                and self.halite >= 1000 and rem > 100 and
                np.sum(game.cells[:, :, 0]) * 3 > self.map_starting_halite):
            ret.append(SpawnShipCommand(self.id, None))
        return ret