def run(self) -> None: location = self.entity.get_map_location() direction_to_deposit = location.direction_to(self._deposit.location) if location == self._deposit.location or location.is_adjacent_to(self._deposit.location): self._deposit.observed_karbonite = GC.get().karbonite_at(self._deposit.location) if self._deposit.observed_karbonite > 0: self._start_harvesting(direction_to_deposit) return if self._deposit.observed_karbonite <= 0: self._update_deposit() if self._deposit is None: return if self._deposit.observed_karbonite <= 0: from states.units.robots.worker.idle import WorkerIdleState self.entity.get_fsm().change_state(WorkerIdleState) if self._path == [] or not GC.get().can_move(self.unit.id, self._path[0]): self._path = PathFinder.get_shortest_path(location, self._deposit.location, False) if self.unit.get_unit().movement_heat() < 10 and self._path != []: next_dir = self._path.pop(0) GC.get().move_robot(self.unit.id, next_dir)
def run(self) -> None: #adjacent_units = GC.get().sense_nearby_units(self.unit.get_map_location(), 2) # building_something = False # for adjacent in adjacent_units: # if GC.get().can_build(self.unit.id, adjacent.id): # GC.get().build(self.unit.id, adjacent.id) # # building_something = True # # if not building_something: # self.unit.get_fsm().change_state(WorkerIdleState(self.unit)) unit_at_building_location = GC.get().sense_unit_at_location(self._build_location) if unit_at_building_location.structure_is_built(): from entities.team import Team Team.instance.add_unit(unit_at_building_location) self.unit.get_fsm().change_state(WorkerIdleState(self.unit)) # if self.unit.get_unit().ability_heat() == 0 and not GC.get().can_build(self.unit.id, unit_at_building_location.id): # print(f"Worker at {self.unit.get_map_location()} cannot continue building {self._build_structure_type} at" # f"{self._build_location}.") # self.unit.get_fsm().change_state(WorkerIdleState(self.unit)) try: GC.get().build(self.unit.id, unit_at_building_location.id) except Exception as e: pass
def _try_shoot_at(self, enemy_id: int) -> bool: if GC.get().can_attack(self.entity.id, enemy_id) and GC.get().is_attack_ready( self.entity.id): GC.get().attack(self.entity.id, enemy_id) return True return False
def get_any_enemy_in_range(entity): vision_range = get_unit_vision_range(entity.get_unit().unit_type) from entities.team import Team visible_enemies = GC.get().sense_nearby_units_by_team(entity.get_map_location(), vision_range, Team.instance.get_opposite_team()) for visible_enemy in visible_enemies: if GC.get().can_attack(entity.id, visible_enemy.id): return visible_enemy return None
def attack_at_random_enemy(entity): if not GC.get().is_attack_ready(entity.id): return vision_range = get_unit_vision_range(entity.get_unit().unit_type) from entities.team import Team visible_enemies = GC.get().sense_nearby_units_by_team(entity.get_map_location(), vision_range, Team.instance.get_opposite_team()) for visible_enemy in visible_enemies: if GC.get().can_attack(visible_enemy.id): GC.get().attack(entity.id, visible_enemy.id)
def __init__(self): super().__init__(TeamEarlyState(self), TeamGlobalState(self)) Team.instance = self for bc_unit in GC.get().my_units(): self.add_unit(bc_unit) if GC.get().planet() == bc.Planet.Earth: self.units[-1] = Researcher() self.map = GC.get().starting_map(GC.get().planet())
def run(self): from states.units.robots.ranger.sensing_enemies import SensingEnemies visible_enemies = SensingEnemies.sense_enemies(self.entity) if len(visible_enemies) == 0: from entities.team import Team from states.units.robots.ranger.move_to_state import MoveToAndSenseEnemiesState self.entity.get_fsm().change_state( MoveToAndSenseEnemiesState( self.entity, Team.instance.get_next_patrol_location())) return # if my target is not visible change my target to nearest and try shoot it, if visible but out of range, shoot at nearest but still pursue it, if in range, shoot it attackable_enemy = None my_target_visible = False my_target_unit = None for visible_enemy in visible_enemies: if visible_enemy.id == self._target_id: my_target_visible = True my_target_unit = visible_enemy if GC.get().can_attack(self.entity.id, visible_enemy.id): attackable_enemy = visible_enemy if attackable_enemy is None: # TODO: it is not attackable but "random" visible then attackable_enemy = visible_enemies[0] if not my_target_visible: self._target_id = attackable_enemy.id if not self._try_shoot_at(self._target_id): self._move_towards_target(attackable_enemy) else: if not self._try_shoot_at(self._target_id): if not self._try_shoot_at(attackable_enemy.id): self._move_towards_target(my_target_unit)
def perform_actions(self): self.get_fsm().update() for unit in GC.get().my_units(): unit_id = unit.id if unit_id not in self.units: self.add_unit(unit) self.units[unit_id].get_fsm().update()
def run(self) -> None: if SensingEnemies.attack_at_random_enemy(self.entity): return if len(self._route) == 0: self.entity.get_fsm().change_state( AttackUnitState(self.entity, self._enemy_id)) return next_step = self._route[0] if GC.get().can_move(self.entity.id, next_step): if self.entity.get_unit().movement_heat() < 10: GC.get().move_robot(self.entity.id, next_step) self._route = self._route[1:] self._stuck_for = 0 else: self._stuck_for += 1 if self._stuck_for > MoveToEnemyState._STUCK_THRESHOLD: self._recompute_route(False)
def run(self) -> None: if SensingEnemies.sense_and_attack(self.entity): return if len(self._route) == 0: self.entity.get_fsm().change_state( StandByAndSenseEnemyState(self.entity)) return next_step = self._route[0] if GC.get().can_move(self.entity.id, next_step): if self.entity.get_unit().movement_heat() < 10: GC.get().move_robot(self.entity.id, next_step) self._route = self._route[1:] self._stuck_for = 0 else: self._stuck_for += 1 if self._stuck_for > MoveToAndSenseEnemiesState._STUCK_THRESHOLD: self._recompute_route(False)
def _choose_best_builder(self, build_structure_type: bc.UnitType) -> (Worker, bc.Direction): # choose worker that is the furthest from the deposit for building builder = None build_direction = None max_dist = 0 for worker in self.team.workers: worker_loc = worker.get_map_location() nearest_dep = GC.get_nearest_karbonite_deposit(worker_loc) path = PathFinder.get_shortest_path(worker_loc, nearest_dep.location, False) for direction in bc.Direction: if (path is None or len(path) > max_dist) and GC.get().can_blueprint(worker.id, build_structure_type, direction): builder = worker build_direction = direction max_dist = len(path) return builder, build_direction
def run(self) -> None: if GC.get().karbonite() > 200 and self.team.factories == [] and self._num_of_sent_builders < 1\ and len(self.team.workers) > 0: # Todo, should also find "best" build spot (builder, build_direction) = self._choose_best_builder(bc.UnitType.Factory) if builder is not None: self._num_of_sent_builders += 1 builder.get_fsm().change_state(BuildingState(builder, bc.UnitType.Factory, build_direction))
def sense_and_attack(entity) -> bool: vision_range = get_unit_vision_range(entity.get_unit().unit_type) from entities.team import Team sensed_units = GC.get().sense_nearby_units_by_team(entity.get_map_location(), vision_range, Team.instance.get_opposite_team()) if len(sensed_units) > 0: some_sensed_unit = sensed_units[0] Team.instance.dispatch_message_to_all(EnemyUnitEncounteredMessage(some_sensed_unit)) entity.get_fsm().change_state(AttackUnitState(entity, some_sensed_unit.id)) return True return False
def run(self) -> None: if self.entity.is_dead(): self._deposit.being_harvested = False self.entity.get_fsm().change_state(DeadState(self.entity)) return self._deposit.observed_karbonite = GC.get().karbonite_at( self._deposit.location) if self._deposit.observed_karbonite <= 0 or self._couldnt_harvest_count > HarvestingState.COULDNT_HARVEST_THRESHOLD: self._deposit.being_harvested = False from states.units.robots.worker.idle import WorkerIdleState self.entity.get_fsm().change_state(WorkerIdleState(self.entity)) return if GC.get().can_harvest(self.entity.id, self._deposit_direction): self._couldnt_harvest_count = 0 GC.get().harvest(self.entity.id, self._deposit_direction) else: self._couldnt_harvest_count += 1
def get_shortest_path(from_location: bc.MapLocation, to_location: bc.MapLocation, ignore_robots: bool): start = Node(from_location.x, from_location.y, bc.Direction.Center, None) searched_locations = set() searched_locations.add((from_location.x, from_location.y)) if (from_location.x == to_location.x and from_location.y == to_location.y) \ or not GC.get_planet_map().on_map(to_location): return [] queue = [start] while len(queue) > 0: first = queue.pop(0) if first.x == to_location.x and first.y == to_location.y: return PathFinder.__build_path_from_node(first) for d in PathFinder.__directions: loc = bc.MapLocation(GC.get().planet(), first.x + d.dx(), first.y + d.dy()) if ( loc.x, loc.y ) in searched_locations or not GC.get_planet_map().on_map(loc): continue if not ignore_robots and GC.get().has_unit_at_location(loc): continue if GC.get_planet_map().is_passable_terrain_at(loc): queue.append(Node(loc.x, loc.y, d, first)) searched_locations.add((loc.x, loc.y)) return [] # todo maybe some exception
def get_next_patrol_location(self) -> bc.MapLocation: x = random.randint(0, self.map.width) y = random.randint(0, self.map.height) return bc.MapLocation(GC.get().planet(), x, y)
def run(self) -> None: nearest_karbonite = GC.get_nearest_karbonite_deposit(self.unit.get_map_location()) if nearest_karbonite is not None: self.entity.get_fsm().change_state(GoingToNearestKarboniteDepositState(self.entity))
def get_unit(self) -> bc.Unit: """ We need this because the battlecode engine recreates all the units after each round, for some reason """ return GC.get().unit(self._unit.id)
def _move_towards_target(self, target: bc.Unit) -> None: if GC.get().is_move_ready(self.entity.id): enemy_direction = self.entity.get_map_location().direction_to( target.location.map_location()) if GC.get().can_move(self.entity.id, enemy_direction): GC.get().move_robot(self.entity.id, enemy_direction)
def run(self) -> None: for direction in list(bc.Direction): if GC.get().can_unload(self.entity.id, direction): GC.get().unload(self.entity.id, direction) self.entity.get_fsm().change_state( FactoryIdleState(self.entity))
def sense_enemies(entity): vision_range = get_unit_vision_range(entity.get_unit().unit_type) from entities.team import Team return GC.get().sense_nearby_units_by_team(entity.get_map_location(), vision_range, Team.instance.get_opposite_team())
import traceback import sys import battlecode as bc import random from ai import AI from game.game_controller import GC from pathfinding.pathfinder import PathFinder random.seed(6137) GC(bc.GameController()) PathFinder() ai = AI() while True: try: ai.play_round() except Exception as e: print(traceback.format_exc()) GC.get().next_turn() # these lines are not strictly necessary, but it helps make the logs make more sense # it forces everything we've written this turn to be written to the manager sys.stdout.flush() sys.stderr.flush()
def _get_current_research_level(self, unit_type: bc.UnitType) -> int: return GC.get().research_info().get_level(unit_type)
def run(self) -> None: unit_type = self._get_unit_type_to_produce() if GC.get().can_produce_robot(self.entity.id, unit_type): GC.get().produce_robot(self.entity.id, unit_type) self.entity.get_fsm().change_state( UnloadingWhenPossibleState(self.entity))
def _enqueue_research(self, unit_type: bc.UnitType): GC.get().queue_research(unit_type)
def run(self) -> None: current_round = GC.get().round() if current_round in self._research_timeline: self._enqueue_research(self._research_timeline[current_round])
def _update_deposit(self): self._deposit = GC.get_nearest_karbonite_deposit(self.entity.get_map_location()) if self._deposit is None: from states.units.robots.worker.idle import WorkerIdleState # TODO: if we are on Earth we may actually stop searching for karbonite deposits because there are none self.entity.get_fsm().change_state(WorkerIdleState(self.entity))
def enter(self): GC.get().blueprint(self.unit.id, self._build_structure_type, self._build_direction) self._build_location = bc.MapLocation(GC.get().planet(), self.unit.get_map_location().x + self._build_direction.dx(), self.unit.get_map_location().y + self._build_direction.dy())
def get_opposite_team(self): my_team = GC.get().team() return bc.Team.Blue if my_team == bc.Team.Red else bc.Team.Red