def isDeadend(self): """ True if path ends in the formation of its deploying player. """ if transform.is_lowerHalf(self.py[0]): return transform.is_lowerHalf(self.py[-1] + 1) else: return transform.is_upperHalf(self.py[-1] - 1)
def _add_stationary_unit(self, pos, attacking=True): """ attacking: True if this unit is a destructor """ x, y = pos if transform.is_lowerHalf(y): for (i, j, r) in self.CIRCLE: if not transform.pos2_inbound((x + i, y + j)): continue p = transform.pos2_encode((x + i, y + j)) if r < self.proximity_self[p]: if attacking: self.proximity_self[p] = r else: self.proximity_self[p] = self.MAX_STATIONARY_RANGE else: for (i, j, r) in self.CIRCLE: if not transform.pos2_inbound((x + i, y + j)): continue p = transform.pos2_encode((x + i, y + j)) if r < self.proximity_enemy[p]: if attacking: self.proximity_enemy[p] = r else: self.proximity_enemy[p] = self.MAX_STATIONARY_RANGE
def markTrajectory(self, path): if not path: return for (x, y) in path: if transform.is_lowerHalf(y): self.prohibited_loc.add((x, y))
def readPaths(self, game_state): self.resetPaths() # Create the pressure map. for p in range(transform.ARENA_SIZE): # Player 1 perspective x, y = transform.pos2_edge_decode(p) if not game_state.contains_stationary_unit([x, y]): # Determine the target edge from x,y. if transform.is_lowerHalf(p): edge = game_state.game_map.TOP_RIGHT else: assert transform.is_upperHalf(p) edge = game_state.game_map.TOP_LEFT path = game_state.find_path_to_edge([x, y], edge) self.path1_self.append(Path.fromGamePath(path)) else: self.path1_self.append(None) # Player 2 persepctive x, y = transform.pos2_flip((x, y)) if not game_state.contains_stationary_unit([x, y]): # Reminder: When p is lower half on the top edge, it # corresponds to TOP_RIGHT! if transform.is_lowerHalf(p): edge = game_state.game_map.BOTTOM_LEFT else: assert transform.is_upperHalf(p) edge = game_state.game_map.BOTTOM_RIGHT path = game_state.find_path_to_edge([x, y], edge) self.path1_enemy.append(Path.fromGamePath(path)) else: self.path1_enemy.append(None) # Check invariants assert len(self.path1_self) == transform.ARENA_SIZE assert len(self.path1_enemy) == transform.ARENA_SIZE self.flag_pathOutdated = False
def _add_destructor_contribution(self, pos): (x, y) = pos if transform.is_lowerHalf(pos[1]): self.number_D_self += 1 for (dx, dy, r) in self.CIRCLE_DESTRUCTOR: if not transform.pos2_inbound((x + dx, y + dy)): continue p = transform.pos2_encode((x + dx, y + dy)) self.barrage_self[p] += 1 else: self.number_D_enemy += 1 for (dx, dy, r) in self.CIRCLE_DESTRUCTOR: if not transform.pos2_inbound((x + dx, y + dy)): continue p = transform.pos2_encode((x + dx, y + dy)) self.barrage_enemy[p] += 1
def readGameState(self, game_state): self.bits_self = game_state.get_resource(game_state.BITS, 0) self.bits_enemy = game_state.get_resource(game_state.BITS, 1) self.cores_self = game_state.get_resource(game_state.CORES, 0) self.cores_enemy = game_state.get_resource(game_state.CORES, 1) self.number_E_self = 0 self.number_E_enemy = 0 self.number_D_self = 0 self.number_D_enemy = 0 # Primary attack trajectories self.primal_self = None self.primal_enemy = None # Set of prohibited locations as determined by the primary trajectory. self.prohibited_loc = set() # Create units map for p in range(transform.ARENA_VOL): self.stability_F[p] = 0 self.stability_E[p] = 0 self.stability_D[p] = 0 self.pressure_self[p] = 0 self.pressure_enemy[p] = 0 self.barrage_self[p] = 0 self.barrage_enemy[p] = 0 self.proximity_self[p] = float('+inf') self.proximity_enemy[p] = float('+inf') x, y = transform.pos2_decode(p) units = game_state.game_map[x, y] for unit in units: stability = unit.stability if not unit.stationary: continue if unit.unit_type == FILTER: self._add_stationary_unit([x, y], attacking=False) self.stability_F[p] = stability elif unit.unit_type == ENCRYPTOR: if transform.is_lowerHalf(y): self.number_E_self += 1 else: self.number_E_enemy += 1 self._add_stationary_unit([x, y], attacking=False) self.stability_E[p] = stability elif unit.unit_type == DESTRUCTOR: self._add_stationary_unit([x, y], attacking=True) self._add_destructor_contribution((x, y)) self.stability_D[p] = stability
def addUnit(self, game_state, pos, unittype): """ Called by spawnDefensiveUnit only. Can only add points in friendly territory """ uid = UNIT_TYPE_TO_INDEX[unittype] assert transform.is_lowerHalf(pos[1]) p = transform.pos2_encode(pos) stability = self.STABILITY[uid] if uid == UNIT_TYPE_TO_INDEX[FILTER]: self._add_stationary_unit(pos, attacking=False) self.stability_F[p] = self.STABILITY[uid] elif uid == UNIT_TYPE_TO_INDEX[ENCRYPTOR]: self._add_stationary_unit(pos, attacking=False) self.stability_E[p] = self.STABILITY[uid] elif uid == UNIT_TYPE_TO_INDEX[DESTRUCTOR]: self._add_stationary_unit(pos, attacking=True) self._add_destructor_contribution(pos) self.stability_D[p] = self.STABILITY[uid]
def _evaluatePath(self, path, nEMP: int = 1): """ Populate the shield,damage field of the path. Populate pressure field. """ if not path: # Path starts from a occupied unit. return float('-inf') path.evaluated = True player = 0 if transform.is_lowerHalf(path.py[0]) else 1 path.feasibility = 0.0 path.shield = 0.0 path.damage = 0.0 path.harass = 0.0 if path.isDeadend: path.feasibility = float('-inf') return path.feasibility # Get list of encryptors if player == 0: encs = self.li_encryptors_self.copy() else: encs = self.li_encryptors_enemy.copy() EMP_STABILITY = self.STABILITY[UNIT_TYPE_TO_INDEX[EMP]] EMP_SPEED = self.SPEED[UNIT_TYPE_TO_INDEX[EMP]] EMP_RANGE = self.RANGE[UNIT_TYPE_TO_INDEX[EMP]] n = len(path) for i in range(n): x = path.px[i] y = path.py[i] p = transform.pos2_encode((x, y)) # Filter the encs list ne = len(encs) encs = [e for e in encs if \ transform.distance2(e, (x,y)) >= \ self.RANGE[UNIT_TYPE_TO_INDEX[ENCRYPTOR]] + 0.51] shield = (ne - len(encs)) * self.ENCRYPTOR_SHIELD path.shield_dp[i] = shield path.shield += shield # Enemy destructor if player == 0: damage = self.barrage_enemy[p] else: damage = self.barrage_self[p] path.damage_dp[i] = damage path.damage += damage if transform.is_lowerHalf(y) == (player == 0): path.dist_self += 1 else: path.dist_enemy += 1 nEMP += shield / EMP_STABILITY nEMP -= damage / EMP_STABILITY / EMP_SPEED path.pressure_dp[i] = nEMP * self.DAMAGE_F_EMP if player == 0: if self.proximity_enemy[p] == EMP_RANGE: path.harass += 1 #gamelib.debug_write('Harassed (Self)') # This is always 0 if transform.is_upperHalf(y): path.pressure_dp[i] -= \ self.stability_F[p] + \ self.stability_E[p] + \ self.stability_D[p] else: if self.proximity_self[p] == EMP_RANGE: path.harass += 1 #gamelib.debug_write('Harassed (Enemy)') # This is always 0 if transform.is_lowerHalf(y): path.pressure_dp[i] -= \ self.stability_F[p] + \ self.stability_E[p] + \ self.stability_D[p] AMBIENT_PRESSURE = self.DAMAGE_F_EMP path.pressure_dp[i] = max(path.pressure_dp[i], AMBIENT_PRESSURE) x_normal, y_normal = path.px[0], path.py[0] if player == 0: policy = self.policy_self else: policy = self.policy_enemy x_normal, y_normal = transform.pos2_flip((x_normal, y_normal)) x_normal /= (transform.ARENA_SIZE - 1) y_normal /= (transform.HALF_ARENA - 1) path.feasibility = policy.w_dist_self * path.dist_self \ - policy.w_dist_enemy * path.dist_enemy \ + policy.w_shield * path.shield \ + policy.w_damage * path.damage \ + policy.w_pos_x * x_normal \ + policy.w_pos_y * y_normal \ + policy.w_harass * path.harass return path.feasibility
def fromGamePath(cls, path): px, py = zip(*path) # Transpose px = array.array('i', px) py = array.array('i', py) player = (0 if transform.is_lowerHalf(py[0]) else 1) return cls(px=px, py=py, player=player)