Example #1
0
    def change_state(self, tank, world, memory, debug_on):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.memory = memory

        self.physics = WorldPhysics(world)
Example #2
0
    def __init__(self,
                 tank,
                 world,
                 position_getters,
                 position_estimators,
                 memory,
                 debug_on=False):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.position_getters = position_getters
        self.position_estimators = position_estimators
        self.memory = memory

        self.physics = WorldPhysics(world)
    def change_state(self, tank, world, memory, debug_on):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.memory = memory

        self.physics = WorldPhysics(world)
    def __init__(self, tank, world, position_getters, position_estimators, memory, debug_on=False):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.position_getters = position_getters
        self.position_estimators = position_estimators
        self.memory = memory

        self.physics = WorldPhysics(world)
class ScalarFieldMovingStrategy:
    def __init__(self, position_getters, position_estimators):
        self.position_getters = position_getters
        self.position_estimators = position_estimators

    def debug(self, message, end='\n',ticks_period=10):
        if self.world.tick % ticks_period == 0:
            if self.debug_mode:
                print(message,end=end)

    def change_state(self, tank, world, memory, debug_on):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.memory = memory

        self.physics = WorldPhysics(world)

    def make_turn(self, move):
        return self._make_turn(self.tank, self.world, move)

    def _make_turn(self, tank, world, move):
        # Precalc for estimation
        self.enemies = list(filter(ALIVE_ENEMY_TANK, world.tanks))
        self.allies = list(filter(ALLY_TANK(tank.id), world.tanks))
        self.health_fraction = tank.crew_health / tank.crew_max_health
        self.hull_fraction = tank.hull_durability / tank.hull_max_durability
        self.enemies_count = len(self.enemies)
        self.est_time_cache = {}

        positions = []
        for pg in self.position_getters:
            positions += pg.positions(tank, world)
        self.debug('Got %d positions' % len(positions))
        if not positions:
            return

        for e in self.position_estimators:
            e.context = self
        pos_and_values = [(pos, sum([e.value(pos) for e in self.position_estimators]))
                          for pos in positions]

        if self.debug_mode:
            top_pos = [item[0] for item in list(reversed(sorted(pos_and_values, key=operator.itemgetter(1))))[:6]]

            self.debug(' ' * 50, end='')
            for e in self.position_estimators:
                self.debug('%14s' % e.NAME, end='')
            self.debug('%14s' % 'RESULT', end='')
            self.debug('')

            def out_pos(pos):
                self.debug('%-50s' % (str(pos) + ' : '), end='')
                res = 0
                for e in self.position_estimators:
                    v = e.value(pos)
                    self.debug('%14.2f' % v, end='')
                    res += v
                self.debug('%14.2f' % res, end='')
                self.debug('')

            for pos in top_pos:
                out_pos(pos)
            self.debug('=' * 16)
            for pos in positions:
                if pos.name.find('BONUS') != -1:
                    out_pos(pos)
            self.debug('=' * 16)
            for pos in positions:
                if pos.name == 'FORWARD' or pos.name == 'BACKWARD' or pos.name == 'CURRENT':
                    out_pos(pos)

            self.debug('=' * 16)
            for pos in positions:
                if pos.name.find('BORDER') != -1:
                    out_pos(pos)


        next_position = None

        position_iteration = 0
        #average_F = sum([pos[0] for pos in pos_f])/len(pos_f)
        pos_queue = PriorityQueue()
        for p_v in pos_and_values:
            pos_queue.put( (-p_v[1] + random() * 1e-3, p_v[0]) )

        while True:
            cur = pos_queue.get()[1]
            if not self.physics.position_is_blocked(cur.x, cur.y, tank, world) or position_iteration >= MAX_POSITION_ITERATIONS:
                next_position = cur
                break
            position_iteration += 1
            self.debug('!!! Skipping best position, iteration %d' % position_iteration)
            if self.debug_mode:
                self.debug('(blocked by %s)' % str(self.physics.position_is_blocked(cur.x, cur.y, tank, world)))

        self.debug("GOING TO [%10s] (%8.2f, %8.2f); distance=%8.2f, ETA=%8.2f" %
                   (next_position.name, next_position.x, next_position.y,
                    self.tank.get_distance_to(next_position.x, next_position.y), self.physics.estimate_time_to_position(next_position.x, next_position.y, tank))
        )
        self.memory.last_target_position[tank.id] = next_position
        self.physics.move_to_position(next_position.x, next_position.y, tank, move)

        self.debug('=' * 16)
        if self.debug_mode:
            for shell in world.shells:
                v0 = hypot(shell.speedX, shell.speedY)
                a = SHELL_ACCELERATION
                d = tank.get_distance_to_unit(shell)
                tank_v = Vector(tank.x, tank.y)
                shell_v = Vector(shell.x, shell.y)
                shell_speed = Vector(shell.speedX, shell.speedY)
                #d = shell.get_distance_to(x, y)
                t = solve_quadratic(a/2, v0, -d)

                self.debug('SHELL [%12s] (%8.2f, %8.2f) v=%s, will hit=%s, hit time=%8.2f' %
                           (shell.player_name, shell.x, shell.y, shell_speed.length(), str(self.physics.shell_will_hit(shell, tank, factor=1.05)), t) )

            self.debug('=' * 16)
Example #6
0
class StrategyScalarField:
    def __init__(self,
                 tank,
                 world,
                 position_getters,
                 position_estimators,
                 memory,
                 debug_on=False):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.position_getters = position_getters
        self.position_estimators = position_estimators
        self.memory = memory

        self.physics = WorldPhysics(world)

    def debug(self, message, end='\n', ticks_period=10):
        if self.world.tick % ticks_period == 0:
            if self.debug_mode:
                print(message, end=end)

    def change_state(self, tank, world, memory, debug_on):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.memory = memory

        self.physics = WorldPhysics(world)

    def make_turn(self, move):
        return self._make_turn(self.tank, self.world, move)

    def _make_turn(self, tank, world, move):
        # Precalc for estimation
        self.enemies = list(filter(ALIVE_ENEMY_TANK, world.tanks))
        self.allies = list(filter(ALLY_TANK(tank.id), world.tanks))
        self.health_fraction = tank.crew_health / tank.crew_max_health
        self.hull_fraction = tank.hull_durability / tank.hull_max_durability
        self.enemies_count = len(self.enemies)
        self.EA_cache = {}
        self.est_time_cache = {}

        def process_moving():
            positions = []
            for pg in self.position_getters:
                positions += pg.positions(tank, world)
            self.debug('Got %d positions' % len(positions))
            if not positions:
                return

            for e in self.position_estimators:
                e.context = self
            pos_and_values = [
                (pos, sum([e.value(pos) for e in self.position_estimators]))
                for pos in positions
            ]

            if self.debug_mode:
                top_pos = [
                    item[0] for item in list(
                        reversed(
                            sorted(pos_and_values, key=operator.itemgetter(
                                1))))[:6]
                ]

                self.debug(' ' * 50, end='')
                for e in self.position_estimators:
                    self.debug('%14s' % e.NAME, end='')
                self.debug('%14s' % 'RESULT', end='')
                self.debug('')

                def out_pos(pos):
                    self.debug('%-50s' % (str(pos) + ' : '), end='')
                    res = 0
                    for e in self.position_estimators:
                        v = e.value(pos)
                        self.debug('%14.2f' % v, end='')
                        res += v
                    self.debug('%14.2f' % res, end='')
                    self.debug('')

                for pos in top_pos:
                    out_pos(pos)
                self.debug('=' * 16)
                for pos in positions:
                    if pos.name.find('BONUS') != -1:
                        out_pos(pos)
                self.debug('=' * 16)
                for pos in positions:
                    if pos.name == 'FORWARD' or pos.name == 'BACKWARD' or pos.name == 'CURRENT':
                        out_pos(pos)

                self.debug('=' * 16)
                for pos in positions:
                    if pos.name.find('BORDER') != -1:
                        out_pos(pos)

            next_position = None

            position_iteration = 0
            #average_F = sum([pos[0] for pos in pos_f])/len(pos_f)
            pos_queue = PriorityQueue()
            for p_v in pos_and_values:
                pos_queue.put((-p_v[1] + random() * 1e-3, p_v[0]))

            while True:
                cur = pos_queue.get()[1]
                if not self.physics.position_is_blocked(
                        cur.x, cur.y, tank, world
                ) or position_iteration >= MAX_POSITION_ITERATIONS:
                    next_position = cur
                    break
                position_iteration += 1
                self.debug('!!! Skipping best position, iteration %d' %
                           position_iteration)
                if self.debug_mode:
                    self.debug('(blocked by %s)' % str(
                        self.physics.position_is_blocked(
                            cur.x, cur.y, tank, world)))

            self.debug(
                "GOING TO [%10s] (%8.2f, %8.2f); distance=%8.2f, ETA=%8.2f" %
                (next_position.name, next_position.x, next_position.y,
                 self.tank.get_distance_to(next_position.x, next_position.y),
                 self.physics.estimate_time_to_position(
                     next_position.x, next_position.y, tank)))
            self.memory.last_target_position[tank.id] = next_position
            self.physics.move_to_position(next_position.x, next_position.y,
                                          tank, move)

        def process_shooting():
            targets = filter(ALIVE_ENEMY_TANK, world.tanks)

            if not targets:
                return

            def get_target_priority(tank, target):
                health_fraction = tank.crew_health / tank.crew_max_health

                # ================
                # DISTANCE
                # ================
                angle_penalty_factor = (
                    1 + (1 - health_fraction) * 1.5 -
                    (1 - max(0, 150 - tank.remaining_reloading_time) / 150) *
                    1)

                angle_degrees = fabs(
                    tank.get_turret_angle_to_unit(target)) / PI * 180

                distance_penalty = tank.get_distance_to_unit(target) / 10
                angle_penalty = angle_penalty_factor * (angle_degrees**1.2) / 2

                # ================
                # FINISH
                # ================
                if ((target.crew_health <= 20 or target.hull_durability <= 20)
                        or (tank.premium_shell_count > 0 and
                            (target.crew_health <= 35
                             or target.hull_durability <= 35))):
                    finish_bonus = 30
                else:
                    finish_bonus = 0

                # ================
                # RESPONSE
                # ================
                if self.physics.attacked_area(
                        tank.x, tank.y, target, cache=self.EA_cache) > 0.5:
                    attacking_me_bonus = 20
                else:
                    attacking_me_bonus = 0

                # ================
                # LAST TARGET
                # ================
                last_target_bonus = 0
                if self.memory.last_turret_target_id:
                    if self.memory.last_turret_target_id == target.id:
                        last_target_bonus = 5

                result = 180 + finish_bonus + attacking_me_bonus + last_target_bonus - distance_penalty - angle_penalty
                self.debug(
                    'TARGET [%20s] (x=%8.2f, y=%8.2f, |v|=%8.2f) finish_B=%8.2f, AM_B=%8.2f, LT_B=%8.2f, D_P=%8.2f, A_P=%8.2f, APF=%8.2f, result=%8.2f'
                    % (target.player_name, target.x, target.y,
                       hypot(target.speedX, target.speedY), finish_bonus,
                       attacking_me_bonus, last_target_bonus, distance_penalty,
                       angle_penalty, angle_penalty_factor, result))
                return result

            if self.debug_mode:
                targets = sorted(targets, key=lambda t: t.player_name)
            targets_f = [(t, get_target_priority(tank, t)) for t in targets]

            cur_target = max(targets_f, key=operator.itemgetter(1))[0]
            self.memory.last_turret_target_id = cur_target.id

            est_pos = self.physics.estimate_target_position(cur_target, tank)

            def bonus_is_attacked():
                for bonus in world.bonuses:
                    if (self.physics.will_hit(tank, bonus, BONUS_FACTOR)
                            and tank.get_distance_to_unit(bonus) <
                            tank.get_distance_to(*est_pos)):
                        return bonus
                return False

            def obstacle_is_attacked():
                obstacles = chain(filter(DEAD_TANK, world.tanks),
                                  filter(ALLY_TANK(tank.id), world.tanks),
                                  world.obstacles)
                for obstacle in obstacles:
                    next_position = self.physics.estimate_target_position(
                        obstacle, tank)
                    next_unit = fictive_unit(obstacle, next_position[0],
                                             next_position[1])

                    blocked = ((self.physics.will_hit(
                        tank, next_unit, DEAD_TANK_OBSTACLE_FACTOR)
                                or self.physics.will_hit(
                                    tank, obstacle, DEAD_TANK_OBSTACLE_FACTOR))
                               and tank.get_distance_to_unit(obstacle) <
                               tank.get_distance_to(*est_pos))
                    if blocked:
                        return obstacle
                return False

            cur_angle = tank.get_turret_angle_to(*est_pos)
            good_to_shoot = self.physics.will_hit(
                tank, fictive_unit(cur_target, est_pos[0], est_pos[1]),
                TARGETING_FACTOR)
            if good_to_shoot:
                if self.health_fraction > 0.8 and self.hull_fraction > 0.5 and tank.get_distance_to_unit(
                        cur_target) > 400 and tank.premium_shell_count <= 3:
                    move.fire_type = FireType.REGULAR
                else:
                    move.fire_type = FireType.PREMIUM_PREFERRED
            else:
                move.fire_type = FireType.NONE

            if bonus_is_attacked() or obstacle_is_attacked():
                self.debug('!!! Obstacle is attacked, don\'t shoot')
                move.fire_type = FireType.NONE

            if world.tick < 10 + tank.teammate_index * 10:
                move.fire_type = FireType.NONE

            if fabs(cur_angle) > PI / 180 * 0.5:
                move.turret_turn = sign(cur_angle)

        process_moving()
        self.debug('=' * 16)
        process_shooting()
class StrategyScalarField:
    def __init__(self, tank, world, position_getters, position_estimators, memory, debug_on=False):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.position_getters = position_getters
        self.position_estimators = position_estimators
        self.memory = memory

        self.physics = WorldPhysics(world)

    def debug(self, message, end='\n',ticks_period=10):
        if self.world.tick % ticks_period == 0:
            if self.debug_mode:
                print(message,end=end)

    def change_state(self, tank, world, memory, debug_on):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.memory = memory

        self.physics = WorldPhysics(world)

    def make_turn(self, move):
        return self._make_turn(self.tank, self.world, move)

    def _make_turn(self, tank, world, move):
        # Precalc for estimation
        self.enemies = list(filter(ALIVE_ENEMY_TANK, world.tanks))
        self.allies = list(filter(ALLY_TANK(tank.id), world.tanks))
        self.health_fraction = tank.crew_health / tank.crew_max_health
        self.hull_fraction = tank.hull_durability / tank.hull_max_durability
        self.enemies_count = len(self.enemies)
        self.EA_cache = {}
        self.est_time_cache = {}

        def process_moving():
            positions = []
            for pg in self.position_getters:
                positions += pg.positions(tank, world)
            self.debug('Got %d positions' % len(positions))
            if not positions:
                return

            for e in self.position_estimators:
                e.context = self
            pos_and_values = [(pos, sum([e.value(pos) for e in self.position_estimators]))
                              for pos in positions]

            if self.debug_mode:
                top_pos = [item[0] for item in list(reversed(sorted(pos_and_values, key=operator.itemgetter(1))))[:6]]

                self.debug(' ' * 50, end='')
                for e in self.position_estimators:
                    self.debug('%14s' % e.NAME, end='')
                self.debug('%14s' % 'RESULT', end='')
                self.debug('')

                def out_pos(pos):
                    self.debug('%-50s' % (str(pos) + ' : '), end='')
                    res = 0
                    for e in self.position_estimators:
                        v = e.value(pos)
                        self.debug('%14.2f' % v, end='')
                        res += v
                    self.debug('%14.2f' % res, end='')
                    self.debug('')

                for pos in top_pos:
                    out_pos(pos)
                self.debug('=' * 16)
                for pos in positions:
                    if pos.name.find('BONUS') != -1:
                        out_pos(pos)
                self.debug('=' * 16)
                for pos in positions:
                    if pos.name == 'FORWARD' or pos.name == 'BACKWARD' or pos.name == 'CURRENT':
                        out_pos(pos)

                self.debug('=' * 16)
                for pos in positions:
                    if pos.name.find('BORDER') != -1:
                        out_pos(pos)


            next_position = None

            position_iteration = 0
            #average_F = sum([pos[0] for pos in pos_f])/len(pos_f)
            pos_queue = PriorityQueue()
            for p_v in pos_and_values:
                pos_queue.put( (-p_v[1] + random() * 1e-3, p_v[0]) )

            while True:
                cur = pos_queue.get()[1]
                if not self.physics.position_is_blocked(cur.x, cur.y, tank, world) or position_iteration >= MAX_POSITION_ITERATIONS:
                    next_position = cur
                    break
                position_iteration += 1
                self.debug('!!! Skipping best position, iteration %d' % position_iteration)
                if self.debug_mode:
                    self.debug('(blocked by %s)' % str(self.physics.position_is_blocked(cur.x, cur.y, tank, world)))

            self.debug("GOING TO [%10s] (%8.2f, %8.2f); distance=%8.2f, ETA=%8.2f" %
                       (next_position.name, next_position.x, next_position.y,
                        self.tank.get_distance_to(next_position.x, next_position.y), self.physics.estimate_time_to_position(next_position.x, next_position.y, tank))
            )
            self.memory.last_target_position[tank.id] = next_position
            self.physics.move_to_position(next_position.x, next_position.y, tank, move)

        def process_shooting():
            targets = filter(ALIVE_ENEMY_TANK, world.tanks)

            if not targets:
                return

            def get_target_priority(tank, target):
                health_fraction = tank.crew_health / tank.crew_max_health

                # ================
                # DISTANCE
                # ================
                angle_penalty_factor = (1 + (1 - health_fraction) * 1.5 -
                                        (1 - max(0, 150 - tank.remaining_reloading_time)/150) * 1)

                angle_degrees = fabs(tank.get_turret_angle_to_unit(target)) / PI * 180

                distance_penalty = tank.get_distance_to_unit(target) / 10
                angle_penalty = angle_penalty_factor * (angle_degrees**1.2)/2

                # ================
                # FINISH
                # ================
                if ((target.crew_health <= 20 or target.hull_durability <= 20) or
                    (tank.premium_shell_count > 0 and (target.crew_health <= 35 or target.hull_durability <= 35))):
                    finish_bonus = 30
                else:
                    finish_bonus = 0

                # ================
                # RESPONSE
                # ================
                if self.physics.attacked_area(tank.x, tank.y, target, cache=self.EA_cache) > 0.5:
                    attacking_me_bonus = 20
                else:
                    attacking_me_bonus = 0

                # ================
                # LAST TARGET
                # ================
                last_target_bonus = 0
                if self.memory.last_turret_target_id:
                    if self.memory.last_turret_target_id == target.id:
                        last_target_bonus = 5

                result = 180 + finish_bonus + attacking_me_bonus + last_target_bonus - distance_penalty - angle_penalty
                self.debug('TARGET [%20s] (x=%8.2f, y=%8.2f, |v|=%8.2f) finish_B=%8.2f, AM_B=%8.2f, LT_B=%8.2f, D_P=%8.2f, A_P=%8.2f, APF=%8.2f, result=%8.2f' %
                           (target.player_name, target.x, target.y, hypot(target.speedX, target.speedY), finish_bonus, attacking_me_bonus, last_target_bonus,
                            distance_penalty, angle_penalty, angle_penalty_factor, result))
                return result

            if self.debug_mode:
                targets = sorted(targets, key=lambda t : t.player_name)
            targets_f = [(t, get_target_priority(tank, t)) for t in targets]

            cur_target = max(targets_f, key=operator.itemgetter(1))[0]
            self.memory.last_turret_target_id = cur_target.id

            est_pos = self.physics.estimate_target_position(cur_target, tank)

            def bonus_is_attacked():
                for bonus in world.bonuses:
                    if (self.physics.will_hit(tank, bonus, BONUS_FACTOR) and
                        tank.get_distance_to_unit(bonus) < tank.get_distance_to(*est_pos)):
                        return bonus
                return False

            def obstacle_is_attacked():
                obstacles = chain(
                    filter(DEAD_TANK, world.tanks),
                    filter(ALLY_TANK(tank.id), world.tanks),
                    world.obstacles
                )
                for obstacle in obstacles:
                    next_position = self.physics.estimate_target_position(obstacle, tank)
                    next_unit = fictive_unit(obstacle, next_position[0], next_position[1])

                    blocked = ((self.physics.will_hit(tank, next_unit, DEAD_TANK_OBSTACLE_FACTOR)
                                or self.physics.will_hit(tank, obstacle, DEAD_TANK_OBSTACLE_FACTOR))
                               and tank.get_distance_to_unit(obstacle) < tank.get_distance_to(*est_pos))
                    if blocked:
                        return obstacle
                return False

            cur_angle = tank.get_turret_angle_to(*est_pos)
            good_to_shoot = self.physics.will_hit(
                tank,
                fictive_unit(cur_target, est_pos[0], est_pos[1]),
                TARGETING_FACTOR
            )
            if good_to_shoot:
                if self.health_fraction > 0.8 and self.hull_fraction > 0.5 and tank.get_distance_to_unit(cur_target) > 400 and tank.premium_shell_count <= 3:
                    move.fire_type = FireType.REGULAR
                else:
                    move.fire_type = FireType.PREMIUM_PREFERRED
            else:
                move.fire_type = FireType.NONE

            if bonus_is_attacked() or obstacle_is_attacked():
                self.debug('!!! Obstacle is attacked, don\'t shoot')
                move.fire_type = FireType.NONE

            if world.tick < 10 + tank.teammate_index * 10:
                move.fire_type = FireType.NONE

            if fabs(cur_angle) > PI/180 * 0.5:
                move.turret_turn = sign(cur_angle)

        process_moving()
        self.debug('=' * 16)
        process_shooting()
class OldTargetingStrategy:

    def __init__(self):
        pass

    def debug(self, message, end='\n',ticks_period=10):
        if self.world.tick % ticks_period == 0:
            if self.debug_mode:
                print(message,end=end)

    def change_state(self, tank, world, memory, debug_on):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.memory = memory

        self.physics = WorldPhysics(world)

    def make_turn(self, move):
        return self._make_turn(self.tank, self.world, move)

    def _make_turn(self, tank, world, move):
        # Precalc for estimation
        self.enemies = list(filter(ALIVE_ENEMY_TANK, world.tanks))
        self.allies = list(filter(ALLY_TANK(tank.id), world.tanks))
        self.health_fraction = tank.crew_health / tank.crew_max_health
        self.hull_fraction = tank.hull_durability / tank.hull_max_durability
        self.enemies_count = len(self.enemies)

        def process_shooting():
            targets = filter(ALIVE_ENEMY_TANK, world.tanks)

            if not targets:
                return

            def get_target_priority(tank, target):
                health_fraction = tank.crew_health / tank.crew_max_health

                # ================
                # DISTANCE
                # ================
                angle_penalty_factor = (1 + (1 - health_fraction) * 1.5 -
                                        (1 - max(0, 150 - tank.remaining_reloading_time)/150) * 1)

                angle_degrees = fabs(tank.get_turret_angle_to_unit(target)) / PI * 180

                distance_penalty = tank.get_distance_to_unit(target) / 10
                angle_penalty = angle_penalty_factor * (angle_degrees**1.2)/2

                # ================
                # FINISH
                # ================
                if ((target.crew_health <= 20 or target.hull_durability <= 20) or
                    (tank.premium_shell_count > 0 and (target.crew_health <= 35 or target.hull_durability <= 35))):
                    finish_bonus = 30
                else:
                    finish_bonus = 0

                # ================
                # RESPONSE
                # ================
                if self.physics.attacked_area(tank.x, tank.y, target, cache=self.EA_cache) > 0.5:
                    attacking_me_bonus = 20
                else:
                    attacking_me_bonus = 0

                # ================
                # LAST TARGET
                # ================
                last_target_bonus = 0
                if self.memory.last_turret_target_id:
                    if self.memory.last_turret_target_id == target.id:
                        last_target_bonus = 5

                result = 180 + finish_bonus + attacking_me_bonus + last_target_bonus - distance_penalty - angle_penalty
                self.debug('TARGET [%20s] (x=%8.2f, y=%8.2f, |v|=%8.2f) finish_B=%8.2f, AM_B=%8.2f, LT_B=%8.2f, D_P=%8.2f, A_P=%8.2f, APF=%8.2f, result=%8.2f' %
                           (target.player_name, target.x, target.y, hypot(target.speedX, target.speedY), finish_bonus, attacking_me_bonus, last_target_bonus,
                            distance_penalty, angle_penalty, angle_penalty_factor, result))
                return result

            if self.debug_mode:
                targets = sorted(targets, key=lambda t : t.player_name)
            targets_f = [(t, get_target_priority(tank, t)) for t in targets]

            cur_target = max(targets_f, key=operator.itemgetter(1))[0]
            self.memory.last_turret_target_id = cur_target.id

            est_pos = self.physics.estimate_target_position(cur_target, tank)

            def bonus_is_attacked():
                for bonus in world.bonuses:
                    if (self.physics.will_hit(tank, bonus, BONUS_FACTOR) and
                        tank.get_distance_to_unit(bonus) < tank.get_distance_to(*est_pos)):
                        return bonus
                return False

            def obstacle_is_attacked():
                obstacles = chain(
                    filter(DEAD_TANK, world.tanks),
                    filter(ALLY_TANK(tank.id), world.tanks),
                    world.obstacles
                )
                for obstacle in obstacles:
                    next_position = self.physics.estimate_target_position(obstacle, tank)
                    next_unit = fictive_unit(obstacle, next_position[0], next_position[1])

                    blocked = ((self.physics.will_hit(tank, next_unit, DEAD_TANK_OBSTACLE_FACTOR)
                                or self.physics.will_hit(tank, obstacle, DEAD_TANK_OBSTACLE_FACTOR))
                               and tank.get_distance_to_unit(obstacle) < tank.get_distance_to(*est_pos))
                    if blocked:
                        return obstacle
                return False

            cur_angle = tank.get_turret_angle_to(*est_pos)
            good_to_shoot = self.physics.will_hit(
                tank,
                fictive_unit(cur_target, est_pos[0], est_pos[1]),
                TARGETING_FACTOR
            )
            if good_to_shoot:
                if self.health_fraction > 0.8 and self.hull_fraction > 0.5 and tank.get_distance_to_unit(cur_target) > 400 and tank.premium_shell_count <= 3:
                    move.fire_type = FireType.REGULAR
                else:
                    move.fire_type = FireType.PREMIUM_PREFERRED
            else:
                move.fire_type = FireType.NONE

            if bonus_is_attacked() or obstacle_is_attacked():
                self.debug('!!! Obstacle is attacked, don\'t shoot')
                move.fire_type = FireType.NONE

            if world.tick < 10 + tank.teammate_index * 10:
                move.fire_type = FireType.NONE

            if fabs(cur_angle) > PI/180 * 0.5:
                move.turret_turn = sign(cur_angle)
        process_shooting()
Example #9
0
class ScalarFieldMovingStrategy:
    def __init__(self, position_getters, position_estimators):
        self.position_getters = position_getters
        self.position_estimators = position_estimators

    def debug(self, message, end='\n', ticks_period=10):
        if self.world.tick % ticks_period == 0:
            if self.debug_mode:
                print(message, end=end)

    def change_state(self, tank, world, memory, debug_on):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.memory = memory

        self.physics = WorldPhysics(world)

    def make_turn(self, move):
        return self._make_turn(self.tank, self.world, move)

    def _make_turn(self, tank, world, move):
        # Precalc for estimation
        self.enemies = list(filter(ALIVE_ENEMY_TANK, world.tanks))
        self.allies = list(filter(ALLY_TANK(tank.id), world.tanks))
        self.health_fraction = tank.crew_health / tank.crew_max_health
        self.hull_fraction = tank.hull_durability / tank.hull_max_durability
        self.enemies_count = len(self.enemies)
        self.est_time_cache = {}

        positions = []
        for pg in self.position_getters:
            positions += pg.positions(tank, world)
        self.debug('Got %d positions' % len(positions))
        if not positions:
            return

        for e in self.position_estimators:
            e.context = self
        pos_and_values = [
            (pos, sum([e.value(pos) for e in self.position_estimators]))
            for pos in positions
        ]

        if self.debug_mode:
            top_pos = [
                item[0] for item in list(
                    reversed(sorted(pos_and_values, key=operator.itemgetter(
                        1))))[:6]
            ]

            self.debug(' ' * 50, end='')
            for e in self.position_estimators:
                self.debug('%14s' % e.NAME, end='')
            self.debug('%14s' % 'RESULT', end='')
            self.debug('')

            def out_pos(pos):
                self.debug('%-50s' % (str(pos) + ' : '), end='')
                res = 0
                for e in self.position_estimators:
                    v = e.value(pos)
                    self.debug('%14.2f' % v, end='')
                    res += v
                self.debug('%14.2f' % res, end='')
                self.debug('')

            for pos in top_pos:
                out_pos(pos)
            self.debug('=' * 16)
            for pos in positions:
                if pos.name.find('BONUS') != -1:
                    out_pos(pos)
            self.debug('=' * 16)
            for pos in positions:
                if pos.name == 'FORWARD' or pos.name == 'BACKWARD' or pos.name == 'CURRENT':
                    out_pos(pos)

            self.debug('=' * 16)
            for pos in positions:
                if pos.name.find('BORDER') != -1:
                    out_pos(pos)

        next_position = None

        position_iteration = 0
        #average_F = sum([pos[0] for pos in pos_f])/len(pos_f)
        pos_queue = PriorityQueue()
        for p_v in pos_and_values:
            pos_queue.put((-p_v[1] + random() * 1e-3, p_v[0]))

        while True:
            cur = pos_queue.get()[1]
            if not self.physics.position_is_blocked(
                    cur.x, cur.y, tank,
                    world) or position_iteration >= MAX_POSITION_ITERATIONS:
                next_position = cur
                break
            position_iteration += 1
            self.debug('!!! Skipping best position, iteration %d' %
                       position_iteration)
            if self.debug_mode:
                self.debug('(blocked by %s)' % str(
                    self.physics.position_is_blocked(cur.x, cur.y, tank,
                                                     world)))

        self.debug(
            "GOING TO [%10s] (%8.2f, %8.2f); distance=%8.2f, ETA=%8.2f" %
            (next_position.name, next_position.x, next_position.y,
             self.tank.get_distance_to(next_position.x, next_position.y),
             self.physics.estimate_time_to_position(next_position.x,
                                                    next_position.y, tank)))
        self.memory.last_target_position[tank.id] = next_position
        self.physics.move_to_position(next_position.x, next_position.y, tank,
                                      move)

        self.debug('=' * 16)
        if self.debug_mode:
            for shell in world.shells:
                v0 = hypot(shell.speedX, shell.speedY)
                a = SHELL_ACCELERATION
                d = tank.get_distance_to_unit(shell)
                tank_v = Vector(tank.x, tank.y)
                shell_v = Vector(shell.x, shell.y)
                shell_speed = Vector(shell.speedX, shell.speedY)
                #d = shell.get_distance_to(x, y)
                t = solve_quadratic(a / 2, v0, -d)

                self.debug(
                    'SHELL [%12s] (%8.2f, %8.2f) v=%s, will hit=%s, hit time=%8.2f'
                    %
                    (shell.player_name, shell.x, shell.y, shell_speed.length(),
                     str(self.physics.shell_will_hit(shell, tank,
                                                     factor=1.05)), t))

            self.debug('=' * 16)
Example #10
0
class OldTargetingStrategy:
    def __init__(self):
        pass

    def debug(self, message, end='\n', ticks_period=10):
        if self.world.tick % ticks_period == 0:
            if self.debug_mode:
                print(message, end=end)

    def change_state(self, tank, world, memory, debug_on):
        self.tank = tank
        self.world = world
        self.debug_mode = debug_on
        self.memory = memory

        self.physics = WorldPhysics(world)

    def make_turn(self, move):
        return self._make_turn(self.tank, self.world, move)

    def _make_turn(self, tank, world, move):
        # Precalc for estimation
        self.enemies = list(filter(ALIVE_ENEMY_TANK, world.tanks))
        self.allies = list(filter(ALLY_TANK(tank.id), world.tanks))
        self.health_fraction = tank.crew_health / tank.crew_max_health
        self.hull_fraction = tank.hull_durability / tank.hull_max_durability
        self.enemies_count = len(self.enemies)

        def process_shooting():
            targets = filter(ALIVE_ENEMY_TANK, world.tanks)

            if not targets:
                return

            def get_target_priority(tank, target):
                health_fraction = tank.crew_health / tank.crew_max_health

                # ================
                # DISTANCE
                # ================
                angle_penalty_factor = (
                    1 + (1 - health_fraction) * 1.5 -
                    (1 - max(0, 150 - tank.remaining_reloading_time) / 150) *
                    1)

                angle_degrees = fabs(
                    tank.get_turret_angle_to_unit(target)) / PI * 180

                distance_penalty = tank.get_distance_to_unit(target) / 10
                angle_penalty = angle_penalty_factor * (angle_degrees**1.2) / 2

                # ================
                # FINISH
                # ================
                if ((target.crew_health <= 20 or target.hull_durability <= 20)
                        or (tank.premium_shell_count > 0 and
                            (target.crew_health <= 35
                             or target.hull_durability <= 35))):
                    finish_bonus = 30
                else:
                    finish_bonus = 0

                # ================
                # RESPONSE
                # ================
                if self.physics.attacked_area(
                        tank.x, tank.y, target, cache=self.EA_cache) > 0.5:
                    attacking_me_bonus = 20
                else:
                    attacking_me_bonus = 0

                # ================
                # LAST TARGET
                # ================
                last_target_bonus = 0
                if self.memory.last_turret_target_id:
                    if self.memory.last_turret_target_id == target.id:
                        last_target_bonus = 5

                result = 180 + finish_bonus + attacking_me_bonus + last_target_bonus - distance_penalty - angle_penalty
                self.debug(
                    'TARGET [%20s] (x=%8.2f, y=%8.2f, |v|=%8.2f) finish_B=%8.2f, AM_B=%8.2f, LT_B=%8.2f, D_P=%8.2f, A_P=%8.2f, APF=%8.2f, result=%8.2f'
                    % (target.player_name, target.x, target.y,
                       hypot(target.speedX, target.speedY), finish_bonus,
                       attacking_me_bonus, last_target_bonus, distance_penalty,
                       angle_penalty, angle_penalty_factor, result))
                return result

            if self.debug_mode:
                targets = sorted(targets, key=lambda t: t.player_name)
            targets_f = [(t, get_target_priority(tank, t)) for t in targets]

            cur_target = max(targets_f, key=operator.itemgetter(1))[0]
            self.memory.last_turret_target_id = cur_target.id

            est_pos = self.physics.estimate_target_position(cur_target, tank)

            def bonus_is_attacked():
                for bonus in world.bonuses:
                    if (self.physics.will_hit(tank, bonus, BONUS_FACTOR)
                            and tank.get_distance_to_unit(bonus) <
                            tank.get_distance_to(*est_pos)):
                        return bonus
                return False

            def obstacle_is_attacked():
                obstacles = chain(filter(DEAD_TANK, world.tanks),
                                  filter(ALLY_TANK(tank.id), world.tanks),
                                  world.obstacles)
                for obstacle in obstacles:
                    next_position = self.physics.estimate_target_position(
                        obstacle, tank)
                    next_unit = fictive_unit(obstacle, next_position[0],
                                             next_position[1])

                    blocked = ((self.physics.will_hit(
                        tank, next_unit, DEAD_TANK_OBSTACLE_FACTOR)
                                or self.physics.will_hit(
                                    tank, obstacle, DEAD_TANK_OBSTACLE_FACTOR))
                               and tank.get_distance_to_unit(obstacle) <
                               tank.get_distance_to(*est_pos))
                    if blocked:
                        return obstacle
                return False

            cur_angle = tank.get_turret_angle_to(*est_pos)
            good_to_shoot = self.physics.will_hit(
                tank, fictive_unit(cur_target, est_pos[0], est_pos[1]),
                TARGETING_FACTOR)
            if good_to_shoot:
                if self.health_fraction > 0.8 and self.hull_fraction > 0.5 and tank.get_distance_to_unit(
                        cur_target) > 400 and tank.premium_shell_count <= 3:
                    move.fire_type = FireType.REGULAR
                else:
                    move.fire_type = FireType.PREMIUM_PREFERRED
            else:
                move.fire_type = FireType.NONE

            if bonus_is_attacked() or obstacle_is_attacked():
                self.debug('!!! Obstacle is attacked, don\'t shoot')
                move.fire_type = FireType.NONE

            if world.tick < 10 + tank.teammate_index * 10:
                move.fire_type = FireType.NONE

            if fabs(cur_angle) > PI / 180 * 0.5:
                move.turret_turn = sign(cur_angle)

        process_shooting()