def apply_go_to_move(point: Point2D, me: Wizard, game: Game, move: Move): """ Простейший способ перемещения волшебника. """ angle = me.get_angle_to(point.x, point.y) move.turn = angle if math.fabs(angle) < game.staff_sector / 4.0: move.speed = game.wizard_forward_speed
def move_to(me: Wizard, world: World, game: Game, move: Move, x: float, y: float): x, y = MyStrategy.avoid_collisions(me, world, x, y) direction_x, direction_y = x - me.x, y - me.y # Normalize the destination vector. distance = math.sqrt(direction_x * direction_x + direction_y * direction_y) if abs(distance) < 1.0: return direction_x /= distance direction_y /= distance # Wizard's turn vector. turn_x, turn_y = math.cos(me.angle), math.sin(me.angle) # Project the destination vector onto the speed vector. speed = direction_x * turn_x + direction_y * turn_y # Project the destination vector onto the strafe speed vector. strafe_speed = direction_x * (-turn_y) + direction_y * turn_x # Finally, set up the movement. max_speed = 10.0 if speed > 0.0: move.speed = speed * max_speed move.strafe_speed = strafe_speed * max_speed else: move.speed = speed * max_speed move.strafe_speed = strafe_speed * max_speed
def move(self, me: Wizard, world: World, game: Game, move: Move): # Every tick, update state first state_machine.update_state(me, world, game) # Take action for this state state_machine.run(me, world, game) # Current state state = state_machine.get_state() # Move move.speed = state.forward_speed move.strafe_speed = state.strafe_speed move.turn = state.turn_angle move.action = state.action
def move(self, me: Wizard, world: World, game: Game, move: Move): if world.tick_index == 0: self.init(me, move, world) return if world.tick_index < 500 and not me.master: if me.messages: for m in me.messages: self.lane = m.lane if world.tick_index == 500 and self.lane is None: self.lane_analysis(world) self.last_tick = world.tick_index move.speed = 0 move.strafe_speed = 0 move.turn = 0 self.x = me.x self.y = me.y self.tower_analysis(world) if world.tick_index - self.last_tick > 500: # check death self.lane_point_index = 0 self.stuck_start_tick = None self.is_fight = False self.lane_analysis(world) # Stuck if self.check_stuck(world.tick_index): self.get_out(move, game) self.debug_func(world) # debug print("stuck") return # Escape if self.check_danger(me): if self.check_if_enemy_near(world, me, game): self.map_master(-1, me) else: # self.map_master(1, me) self.wait_status = True return self.step_point_x, self.step_point_y = self.find_way(world, me) self.go(me, move, game) self.debug_func(world) # debug print("escape") return # Fight # TODO: уклонение от вражеских снарядов, # TODO: хитрая система отхода с максимзацией получаемого опыта # TODO: удар посохом # TODO: учёт бонусов на врагах # TODO: не всегда стрелять!? self.is_fight, enemy, distance_to_closest_minion, tower_near, wizards_amount = self.situation_analysis( world, me) if self.is_fight: self.attack(move, game, me, enemy) if (me.life < me.max_life*0.5) or \ (distance_to_closest_minion < 200) or \ ((type(enemy) is Wizard) and (me.life < enemy.life)) or \ (wizards_amount > 1): self.map_master(-1, me) self.step_point_x, self.step_point_y = self.find_way(world, me) self.go_back(me, move, game) else: if distance_to_closest_minion > 500 - 380 * (me.life / me.max_life)**2: if not tower_near and (wizards_amount <= 1) and ( type(enemy) is not MinionType.FETISH_BLOWDART): self.target_point_x, self.target_point_y = enemy.x, enemy.y self.step_point_x, self.step_point_y = self.find_way( world, me) self.go(me, move, game) self.debug_func(world) # debug print("fight") return # GO if world.tick_index < 1500 - int( self.lane == LaneType.MIDDLE) * 250: # wait for minions if me.y < 450 + me.x: self.map_master(-1, me) else: self.map_master(1, me) else: self.map_master(1, me) self.step_point_x, self.step_point_y = self.find_way(world, me) self.go(me, move, game) self.debug_func(world) # debug print("GO")
def move(self, me: Wizard, world: World, game: Game, move: Move): move.speed = game.wizard_forward_speed move.strafe_speed = game.wizard_strafe_speed move.turn = game.wizard_max_turn_angle move.action = ActionType.MAGIC_MISSILE
def move(self, me: Wizard, world: World, game: Game, move: Move): self.initTick( me, world, game, move ) self.debugFeatures(); if self.state == PlayerState.CHECK_BONUSES: if not self.walk_reached: if self.bonus_index != -1 and self.target_waypoint != self.center_point: if self.isVisible(self.target_waypoint, game.bonus_radius) and (world.tick_index > self.check_time + self.bonus_predict_time): print( 'I can see bonus!' ) target_bonus = list( filter( lambda x: self.target_waypoint.x == x.x and self.target_waypoint.y == x.y, world.bonuses ) ) if not target_bonus: if self.bonus_index == 0: self.bonus_index = 1 self.target_waypoint = self.bonus_points[self.bonus_index] else: self.target_waypoint = self.center_point if me.get_distance_to_unit(self.target_waypoint) < (self.wp_radius * 2 if self.target_waypoint == self.center_point \ else game.bonus_radius + me.radius): print( 'Reached' ) if self.target_waypoint in self.bonus_points: print( 'Go to center' ) self.target_waypoint = self.center_point else: self.walk_reached = True else: self.goToWaypointWithAttackNear( self.target_waypoint ) else: if self.bonus_index == -1: if self.current_lane == LaneType.MIDDLE or self.current_lane == LaneType.TOP: self.bonus_index = 0 else: self.bonus_index = 1 self.target_waypoint = self.bonus_points[self.bonus_index] self.walk_reached = False elif self.bonus_index == 0: self.bonus_index = 1 if self.current_lane == LaneType.MIDDLE: self.target_waypoint = self.bonus_points[self.bonus_index] self.walk_reached = False else: self.state = PlayerState.WALK_FORWARD if self.isEnemyInRange(game.wizard_vision_range): self.state = PlayerState.BATTLE print('Found enemy!') return if self.state == PlayerState.WALK_TO_BASE: if not self.walk_reached: if me.get_distance_to_unit(self.target_waypoint) < self.wp_radius: self.walk_reached = True if self.target_waypoint != self.base_point: self.target_waypoint = self.getPreviousWP() self.walk_reached = False else: self.goToWaypointWithAttackNear( self.target_waypoint ) if self.target_waypoint == self.base_point and self.isEnemyInRange( game.wizard_vision_range * 1.5 ): self.state = PlayerState.BATTLE print('Found enemy!') return else: if self.change_lane: self.setLane( (self.current_lane + 1) % 3 ) self.change_lane = False self.state = PlayerState.WALK_FORWARD return if self.state == PlayerState.WALK_FORWARD: next_wp = self.getNextWP() self.goToWaypointWithAttackNear( next_wp ) self.checkReachedLastWP() self.checkBaseUnderAttack() self.checkBonuses() if self.isEnemyInRange( game.wizard_vision_range * 1.5 ): self.state = PlayerState.BATTLE print('Found enemy!') return near_friendly = [] near_friendly.extend( self.friendly_wizards ) near_friendly.extend( self.friendly_minions ) near_friendly = list(filter( lambda x: x.get_distance_to_unit(next_wp) < me.get_distance_to_unit(next_wp), near_friendly)) if world.tick_index < 1500: if next_wp == self.center_point and me.get_distance_to_unit( next_wp ) < 600 and len( near_friendly ) < 2: move.speed = 0 move.strafe_speed = 0 return if self.state == PlayerState.BATTLE: self.checkReachedLastWP() self.checkBaseUnderAttack() self.checkBonuses() if self.isNearBase(): lane = self.calculateCurrentLane( me ) self.setLane( lane ) if not self.isEnemyInRange( game.wizard_vision_range * 1.5 ): self.state = PlayerState.WALK_FORWARD return target = self.getNearestEnemy() near_weak_enemies = list( filter( lambda x: self.isTargetInCastRange(x) and \ x.life <= game.magic_missile_direct_damage * 2, self.enemy_units ) ) enemy_minions_in_attack_range = \ list( filter( lambda x: x.faction != me.faction and x.faction != Faction.NEUTRAL and \ x.get_distance_to_unit( me ) <= \ (game.orc_woodcutter_attack_range if x.type == MinionType.ORC_WOODCUTTER \ else game.fetish_blowdart_attack_range) + x.radius + me.radius, world.minions ) ) enemy_wizards_on_target = \ list( filter( lambda x: x.get_distance_to_unit( me ) <= game.wizard_vision_range and \ abs(x.get_angle_to_unit( me )) < (game.staff_sector / 2.), self.enemy_wizards ) ) enemies_in_staff_range = list( filter( lambda x: self.isTargetInStaffRange(x), self.enemy_units ) ) enemy_wizards_in_cast_range = list( filter( lambda x: self.isTargetInCastRange(x), self.enemy_wizards ) ) enemies_in_cast_range = list( filter( lambda x: self.isTargetInCastRange(x), self.enemy_units ) ) # if self.enemy_wizards and not enemy_minions_in_attack_range: # nearest_enemy_wizard = min( self.enemy_wizards, key=lambda x: me.get_distance_to_unit( x ) ) # if me.get_distance_to_unit( nearest_enemy_wizard ) <= game.wizard_vision_range: # target = nearest_enemy_wizard # if near_weak_enemies and not enemy_minions_in_attack_range: # enemy_wizards_in_attack_range = \ # list( filter( lambda x: x.get_distance_to_unit( me ) < game.wizard_cast_range + me.radius and \ # x != near_weak_enemies[0], self.enemy_wizards ) ) # if not enemy_wizards_in_attack_range: # target = near_weak_enemies[0] # self.attackTarget( target ) if self.isHealthLow(0.4): self.keepDistanceToUnit( self.getNearestEnemy(), game.wizard_vision_range ) if enemy_wizards_in_cast_range: nearest_wiz = min( enemy_wizards_in_cast_range, key=lambda x: me.get_distance_to_unit(x) ) self.attackTarget( nearest_wiz ) elif enemies_in_cast_range: nearest = min( enemies_in_cast_range, key=lambda x: me.get_distance_to_unit(x) ) self.attackTarget( nearest ) elif len(enemy_wizards_on_target) > 2: nearest_wiz = min( enemy_wizards_on_target, key=lambda x: me.get_distance_to_unit(x) ) self.stepBackFromUnit( nearest_wiz, game.wizard_cast_range + (me.radius + target.radius) ) if enemy_wizards_in_cast_range: nearest_wiz = min( enemy_wizards_in_cast_range, key=lambda x: me.get_distance_to_unit(x) ) self.attackTarget( nearest_wiz ) elif enemies_in_cast_range: nearest = min( enemies_in_cast_range, key=lambda x: me.get_distance_to_unit(x) ) self.attackTarget( nearest ) elif len(enemy_minions_in_attack_range) >= 2: nearest = min( enemy_minions_in_attack_range, key=lambda x: me.get_distance_to_unit(x) ) self.stepBackFromUnit( nearest, (game.orc_woodcutter_attack_range if nearest.type == MinionType.ORC_WOODCUTTER \ else game.fetish_blowdart_attack_range) + nearest.radius + me.radius ) if enemy_wizards_in_cast_range: nearest_wiz = min( enemy_wizards_in_cast_range, key=lambda x: me.get_distance_to_unit(x) ) self.attackTarget( nearest_wiz ) elif enemies_in_cast_range: nearest = min( enemies_in_cast_range, key=lambda x: me.get_distance_to_unit(x) ) self.attackTarget( nearest ) elif not enemies_in_cast_range: nearest = self.getNearestEnemy() self.goForwardToUnit( nearest, game.wizard_cast_range - (me.radius + target.radius) ) self.attackTarget( nearest ) else: if self.isMagicMissileReady(): if enemy_wizards_in_cast_range: nearest_wiz = min( enemy_wizards_in_cast_range, key=lambda x: me.get_distance_to_unit(x) ) self.goForwardToUnit( nearest_wiz, game.wizard_cast_range - (me.radius + target.radius) ) self.attackTarget( nearest_wiz ) elif enemies_in_cast_range: nearest = min( enemies_in_cast_range, key=lambda x: me.get_distance_to_unit(x) ) if not self.isHealthLow(0.6): self.goForwardToUnit( nearest, game.staff_range + (me.radius + target.radius) ) self.attackTarget( nearest ) else: if len(enemy_wizards_on_target) > 0: nearest_wiz = min( enemy_wizards_on_target, key=lambda x: me.get_distance_to_unit(x) ) self.stepBackFromUnit( nearest_wiz, game.wizard_cast_range + (me.radius + target.radius) ) elif enemies_in_staff_range: nearest = min( enemies_in_staff_range, key=lambda x: me.get_distance_to_unit(x) ) self.attackTarget( nearest ) elif enemies_in_cast_range: nearest = min( enemies_in_cast_range, key=lambda x: me.get_distance_to_unit(x) ) if not self.isHealthLow(0.6): self.goForwardToUnit( nearest, game.staff_range + (me.radius) ) self.attackTarget( nearest ) safe_tower_distance = game.guardian_tower_attack_range + me.radius * 2 + game.guardian_tower_radius near_enemy_tower = next((x for x in world.buildings if me.get_distance_to_unit( x ) <= safe_tower_distance and x.faction != me.faction), None) if near_enemy_tower: if near_enemy_tower.life > near_enemy_tower.max_life * 0.25: if me.life > near_enemy_tower.damage: friend_minions_near_tower = list( filter( lambda x: near_enemy_tower.get_distance_to_unit( me ) > near_enemy_tower.get_distance_to_unit( x ), self.friendly_minions ) ) if len( friend_minions_near_tower ) < 2 and near_enemy_tower.remaining_action_cooldown_ticks < 150: self.stepBackFromUnit( near_enemy_tower, safe_tower_distance ) else: if near_enemy_tower.remaining_action_cooldown_ticks < 200: self.stepBackFromUnit( near_enemy_tower, safe_tower_distance ) return
def go_to(self, move: Move, point: Point2D, angle=None, note_angle=False): move.speed, move.strafe_speed, move.turn = self.map.get_optimal_move( point, angle, note_angle)
def move(self, me: Wizard, world: World, game: Game, move: Move): self.log('TICK %s' % world.tick_index) self._init(game, me, world, move) self.log('me %s %s %f' % (me.x, me.y, me.get_distance_to(*self.INIT_POINT))) # initial cooldown if self.PASS_TICK_COUNT: self.PASS_TICK_COUNT -= 1 self.log('initial cooldown pass turn') return # select lane self._select_lane(me) # STRATEGY LOGIC enemy_targets = self._enemies_in_attack_distance(me) enemy_who_can_attack_me = self._enemies_who_can_attack_me(me) retreat_move_lock = False retreat_by_low_hp = False # чистим уже погибшие снаряды из карты current_projectiles_id = set( [p.id for p in self.W.projectiles if p.owner_unit_id == me.id]) cached_projectiles_id = set(self.PROJECTILE_MAP.keys()) for k in cached_projectiles_id - current_projectiles_id: del self.PROJECTILE_MAP[k] # ищем последний созданный снаряд и его цель для карты снарядов if self.PROJECTILE_LAST_ENEMY: for p in self.W.projectiles: if p.owner_unit_id == me.id and p.id not in self.PROJECTILE_MAP: self.PROJECTILE_MAP[p.id] = self.PROJECTILE_LAST_ENEMY self.PROJECTILE_LAST_ENEMY = None break self.log('projectile map %s' % str(self.PROJECTILE_MAP)) # если ХП мало отступаем if me.life < me.max_life * self.LOW_HP_FACTOR: retreat_by_low_hp = True self.log('retreat by low HP') if len(enemy_who_can_attack_me): self._goto_backward(me) retreat_move_lock = True if len(enemy_who_can_attack_me) > self.MAX_ENEMIES_IN_DANGER_ZONE: self.log('retreat by enemies in danger zone') self._goto_backward(me) retreat_move_lock = True # если врагов в радиусе обстрела нет - идём к их базе если не находимся в режиме отступления if not enemy_targets and not retreat_by_low_hp: self.log('move to next waypoint') self._goto_forward(me) # если на поле есть наши снаряды и расстояние до цели меньше расстояния каста # пробуем подойти к цели (если не находимся в отступлении) if not retreat_by_low_hp: potential_miss_enemies = self._find_potential_miss_enemy(me) self.log('found %s potential miss enemies' % potential_miss_enemies) if potential_miss_enemies: e = self._sort_by_angle(me, potential_miss_enemies)[0] self._goto_enemy(me, e) if enemy_targets: # есть враги в радиусе обстрела self.log('found %d enemies for attack' % len(enemy_targets)) selected_enemy = self._select_enemy_for_attack(me, enemy_targets) angle_to_enemy = me.get_angle_to_unit(selected_enemy) # если цель не в секторе атаки - поворачиваемся к ней (приоритет за направлением на точку отступления) if not self._enemy_in_attack_sector(me, selected_enemy): if not retreat_move_lock: self.log('select enemy for turn %s' % selected_enemy.id) self.MOVE_TURN = angle_to_enemy else: self.log('ignore select enemy for turn %s by retreat' % selected_enemy.id) else: # если можем атаковать - атакуем self.log('select enemy for attack %s' % selected_enemy.id) move.cast_angle = angle_to_enemy if self._enemy_in_cast_distance(me, selected_enemy): self.log('cast attack') move.action = ActionType.MAGIC_MISSILE move.min_cast_distance = self._cast_distance( me, selected_enemy) self.PROJECTILE_LAST_ENEMY = selected_enemy.id else: self.log('staff attack') move.action = ActionType.STAFF if self.MOVE_TURN is not None: move.turn = self.MOVE_TURN self.MOVE_TURN = None if self.MOVE_SPEED is not None: move.speed = self.MOVE_SPEED self.MOVE_SPEED = None if self.MOVE_STRAFE_SPEED is not None: move.strafe_speed = self.MOVE_STRAFE_SPEED self.MOVE_STRAFE_SPEED = None