def initialize(self): """Use this function to setup your bot before the game starts.""" self.verbose = True # display the command descriptions next to the bot labels self.attackers = set() self.flagBearers = set() self.fulltimeToRespawn = self.game.match.timeToNextRespawn # Calculate flag positions and store the middle. ours = self.game.team.flagScoreLocation theirs = self.game.enemyTeam.flagScoreLocation self.middle = (theirs + ours) / 2.0 # Now figure out the flaking directions, assumed perpendicular. d = (ours - theirs) self.left = Vector2(-d.y, d.x).normalized() self.right = Vector2(d.y, -d.x).normalized() self.front = Vector2(d.x, d.y).normalized() self.lastNumOfAttackers = 0 self.numOfBotsInital = len(self.game.bots_alive) self.maxDefenders = self.numOfBotsInital -1 self.attackersLast = self.maxDefenders numOfBotsAlive = len(self.game.bots_alive) # for all bots which aren't currently doing anything for bot in self.game.bots_available: if len(self.attackers) < self.maxDefenders: self.attackers.add(Bot(bot)) else: self.flagBearers.add(Bot(bot))
def tick(self): self.parseCombatEvents() if(self.timeToRespawn < self.game.match.timeToNextRespawn ): self.numEnemies = len(self.game.bots_alive) self.timeToRespawn = self.game.match.timeToNextRespawn for bot in self.game.team.members: if bot.health <= 0: self.myAttackers.discard(bot) self.myDefenders.discard(bot) self.facingAttackers.pop(bot, None) for bot in self.game.bots_available: if bot in self.myDefenders or ((len(self.myDefenders)<self.maxDefenders) and len(self.myDefenders) <= self.numEnemies): distanceToHomeFlag = Vector2.distance(bot.position,self.game.team.flagSpawnLocation) distanceToEnemyFlag = Vector2.distance(bot.position, self.game.enemyTeam.flagSpawnLocation) if distanceToEnemyFlag > distanceToHomeFlag or len(self.myAttackers) >= 3: self.goDefend(bot) else: self.goAttack(bot) else: self.goAttack(bot) for bot in self.game.bots_alive: if bot.state == bot.STATE_SHOOTING: continue if bot.state == bot.STATE_TAKINGORDERS: continue if bot.state == bot.STATE_DEFENDING and bot.flag : self.goAttack(bot) continue if (bot in self.myDefenders): self.defenseTick(bot) if (bot in self.myAttackers): self.attackTick(bot)
def goAttack(self, bot): self.myAttackers.add(bot) self.myDefenders.discard(bot) self.resetDefenders() distanceToHomeFlag = Vector2.distance(bot.position,self.game.team.flagSpawnLocation) distanceToEnemyFlag = Vector2.distance(bot.position, self.game.enemyTeam.flagSpawnLocation) enemyFlagSpawn = self.game.enemyTeam.flagSpawnLocation enemyFlag = self.game.enemyTeam.flag.position if not self.attackCloseEnemy(bot): if bot.flag: # Tell the flag carrier to run home! target = self.game.team.flagScoreLocation self.issueAndStore(commands.Move, bot, target, description = 'running home') else: if self.game.enemyTeam.flag.carrier == None: if distanceToEnemyFlag > self.level.firingDistance*1.6: pos1 = self.attackPositions[0] self.attackPositions = self.attackPositions[1:] + [self.attackPositions[0]] pos2 = self.attackPositions[0] self.attackPositions = self.attackPositions[1:] + [self.attackPositions[0]] position = min([pos1,pos2], key=lambda x:Vector2.distance(bot.position,x)) position = self.level.findNearestFreePosition(position) self.issueAndStore(commands.Charge, bot, position, description = 'charge to attack position') else: self.issueAndStore(commands.Charge, bot, enemyFlag,enemyFlag, description = 'Charge enemy flag') else: if distanceToEnemyFlag <= self.level.characterRadius: faceSpawn1 = self.game.enemyTeam.botSpawnArea[0]-bot.position faceSpawn2 = self.game.enemyTeam.botSpawnArea[1]-bot.position faceMiddle = Vector2(self.level.width/2,self.level.height/2)-bot.position faceDirs = [faceSpawn1,faceMiddle] self.issueAndStore(commands.Defend, bot, faceDirs, description = 'defend enemy flag') else: self.issueAndStore(commands.Charge, bot, enemyFlagSpawn, description = 'charge to enemy flagSpawn')
def calculate_nodes_in_range(instance, last_position, time_since, enemy_speed): max_distance = time_since * enemy_speed if max_distance > 55: max_distance = 55 #Get bounds for the inital square of nodes to search. left_bound = int(max(1, last_position.x - max_distance)) right_bound = int(min(88, last_position.x + max_distance)) top_bound = int(min(50, last_position.y + max_distance)) lower_bound = int(max(1, last_position.y - max_distance)) ## print "enemy_speed: ", enemy_speed ## print "time_since: ", time_since ## print "left_bound: ", left_bound ## print "right_bound: " , right_bound ## print "top_bound: ", top_bound ## print "lower_bound: ", lower_bound #Find nodes in initial square, and prune those that are out of range. (The square's corners.) possible_nodes = set() for x in range(left_bound, right_bound): for y in range(lower_bound, top_bound): distance_vector = Vector2(x, y) - last_position if distance_vector.length() > max_distance: continue elif instance.level.blockHeights[int(x)][int(y)] > 0: continue #@terrain node_index = regressions2.get_node_index(instance, Vector2(x, y)) possible_nodes.add(node_index) return possible_nodes
def account_for_spawns(instance, at_large_enemies): #Updates positions of enemies whose health is ostensibly 0 based on if they have respawned. #Dead enemies that have respawned still appear as health 0, and are very much a threat! for enemy_info in at_large_enemies: if enemy_info[0].health == 0 or None: #See if bot has respawned since it was killed. respawned_time = get_respawn(instance, enemy_info[0]) #If the bot respawned figure count its last seen as the center of its respawn. if respawned_time != None: enemy_spawn_coord = Vector2.midPoint(instance.game.enemyTeam.botSpawnArea[0], instance.game.enemyTeam.botSpawnArea[1]) enemy_info[1] = enemy_spawn_coord enemy_info[2] = instance.game.match.timePassed - respawned_time + .5 #If the bot is respawning in the next two seconds, count its last seen as the center of its respawn. elif instance.game.match.timeToNextRespawn < 2.00: enemy_spawn_coord = Vector2.midPoint(instance.game.enemyTeam.botSpawnArea[0], instance.game.enemyTeam.botSpawnArea[1]) enemy_info[1] = enemy_spawn_coord enemy_info[2] = 2.0 #If the game has just begun and the bot is chilling in his spawn, assign him as there. #TODO better spawn positioning. elif enemy_info[0].state == 0: enemy_spawn_coord = Vector2.midPoint(instance.game.enemyTeam.botSpawnArea[0], instance.game.enemyTeam.botSpawnArea[1]) enemy_info[1] = enemy_spawn_coord enemy_info[2] = -1.5 #This is a hack so that we evaluate enemy bots as present at the start. It works pretty well. #If none of the above are true, the bot is dead and we don't need to worry about him. else: at_large_enemies.remove(enemy_info) ## print at_large_enemies return at_large_enemies
def attackCloseEnemy(self, bot): closestEnemy = self.closestEnemy(bot) if closestEnemy is not None and not self.isInsideSpawn(closestEnemy): if bot.flag: enemyDistanceFromHome = Vector2.distance(closestEnemy.position,self.game.team.flagScoreLocation) botDistanceFromHome = Vector2.distance(bot.position,self.game.team.flagScoreLocation) if closestEnemy in bot.seenBy or enemyDistanceFromHome > botDistanceFromHome: return False enemyDistance = Vector2.distance(closestEnemy.position,bot.position) if closestEnemy.state == closestEnemy.STATE_DEFENDING and closestEnemy in bot.seenBy: if enemyDistance < self.level.firingDistance*1.4 and enemyDistance > self.level.firingDistance: enemyDir = (closestEnemy.position - bot.position).normalized() perpendicular = enemyDir.perpendicular().normalized() flank = bot.position + enemyDir*2 + perpendicular*6*self.isLeftOf(bot,closestEnemy) flank = self.level.findNearestFreePosition(flank) if flank is not None: if self.lastCommand[bot] != 'attack defender' or Vector2.distance(bot.position,self.lastTarget[bot])<self.level.characterRadius: self.issueAndStore(commands.Attack, bot, flank,closestEnemy.position, description = 'attack defender') return True if enemyDistance < self.level.firingDistance*1.7 and bot.state in [bot.STATE_MOVING,bot.STATE_IDLE,bot.STATE_CHARGING]: if bot.state is bot.STATE_CHARGING and enemyDistance <= self.level.firingDistance: return False if closestEnemy.state in [closestEnemy.STATE_DEFENDING,closestEnemy.STATE_IDLE,closestEnemy.STATE_TAKINGORDERS]: self.issueAndStore(commands.Attack, bot, closestEnemy.position,closestEnemy.position, description = 'attack close enemy') else: self.issueAndStore(commands.Attack, bot, self.getPositionInFrontOf(closestEnemy),self.getPositionInFrontOf(closestEnemy), description = 'attack close enemy') return True return False return False
def ywave_internal(self, p, upper, lower, direction): for (ux, uy), (lx, ly) in izip(upper, lower): assert uy == ly, "{} != {}".format(uy, ly) y = uy if ux > lx: ux, lx = lx, ux if y < 0: break if y >= self.height: break waves = [] visible = [] blocks = False for x in range(max(ux, 0), min(lx + 1, self.width)): if self.isBlocked(x, y): blocks = True if visible: waves.append(visible) visible = [] else: pass else: visible.append((x, y)) self.setVisible(x, y) if visible: waves.append(visible) visible = [] if blocks: for i, w in enumerate(waves): w0, wn = Vector2(w[0][0] + 0.5, w[0][1] + 0.5), Vector2( w[-1][0] + 0.5, w[-1][1] + 0.5) u = w0 - p l = wn - p u = u / abs(u.y) l = l / abs(l.y) if abs(u.x) > abs(u.y): u.x = abs(u.y) * sign(u.x) if abs(l.x) > abs(l.y): l.x = abs(l.y) * sign(l.x) w0 += u wn += l if i > 0 or w[0][0] > max(ux, 0): uppr = line(w0, w0 + u, finite=False, covering=False) else: uppr = upper if i < len(waves) - 1 or w[-1][0] < min( lx + 1, self.width) - 1: lowr = line(wn, wn + l, finite=False, covering=False) else: lowr = lower self.ywave_internal(p, uppr, lowr, direction) return
def isVisibleFrom(self, pos1, pos2): if Vector2.distance(pos1,pos2) > self.level.firingDistance: return False point = pos1 dir = (pos2 - pos1).normalized() if self.level.blockHeights[int(point.x)][int(point.y)] > 1: point = point + dir while Vector2.distance(point, pos2) > 1: point = point + dir if self.level.blockHeights[int(point.x)][int(point.y)] > 1: return False return True
def get_exit_paths(instance): start, finish = instance.level.botSpawnAreas[instance.game.enemyTeam.name] enemy_base = Vector2(start.x, start.y) instance.graph.add_node("enemy_base", position=(start.x, start.y), weight=0.0) instance.graph.node["enemy_base"]["exit_path"] = 0.0 instance.graph.node["enemy_base"]["camp_target"] = 0.0 instance.graph.node["enemy_base"]["camp_location"] = 0.0 for i, j in itertools.product(range(int(start.x), int(finish.x)), range(int(start.y), int(finish.y))): instance.graph.add_edge("enemy_base", instance.terrain[j][i], weight=1.0) our_flag_node = regressions2.get_node_index( instance, instance.game.team.flag.position) enemy_score_node = regressions2.get_node_index( instance, instance.game.enemyTeam.flagScoreLocation) enemy_flag_node = regressions2.get_node_index( instance, instance.game.enemyTeam.flag.position) our_score_node = regressions2.get_node_index( instance, instance.game.team.flagScoreLocation) b_to_flag = nx.shortest_path(instance.graph, source="enemy_base", target=our_flag_node) b_to_def = nx.shortest_path(instance.graph, source="enemy_base", target=enemy_flag_node) b_to_def2 = nx.shortest_path(instance.graph, source="enemy_base", target=our_score_node) #Calculate how the enemy is exiting from their base. exit_paths = [(b_to_flag, 10), (b_to_def, 6), (b_to_def2, 2)] for x in range(50): position = instance.level.findRandomFreePositionInBox( instance.level.area) base_seperation = position - enemy_base base_seperation = base_seperation * 15 / base_seperation.length() close_pos = enemy_base + base_seperation x, y = regressions2.sanitize_position(instance, close_pos) close_pos = Vector2(x, y) node_index = regressions2.get_node_index(instance, close_pos) path = nx.shortest_path(instance.graph, source="enemy_base", target=node_index) exit_paths.append((path, 4)) return exit_paths
def findFree(self, v): target = v for r in range(1, 50): scale = self.level.characterRadius / 2.0 areaMin = Vector2(target.x - r * scale, target.y - r * scale) areaMax = Vector2(target.x + r * scale, target.y + r * scale) for _ in range(10): position = self.level.findRandomFreePositionInBox( (areaMin, areaMax)) if position: self.log.debug( "findFree had to search out to {}".format(r)) return position return None
def getCandidateActions(self, state): """Use random distribution across map to find potential points, add current action, defend facing a random set of directions. Alongside projected action by doing nothing.""" bot = state actions = [] for x in range(10): position = self.level.findRandomFreePositionInBox(self.level.area) #Add random attack positions. actions.append( [commands.Attack, bot, position, "Attacking selected point."]) #Add defend commands with random directions. direction = Vector2(random.random() * random.sample([-1, 1], 1)[0], random.random() * random.sample([-1, 1], 1)[0]) actions.append([ commands.Defend, bot, direction, "Defending facing random direction." ]) #Add random move commands. actions.append( [commands.Move, bot, position, "Moving to selected point."]) #Add random charge commands. actions.append([ commands.Charge, bot, position, "Charging to selected point." ]) #Add current action string as an option. Parsed to special action that continues to execute current command. actions.append(['currentAction']) return actions
def sanitize_position(instance, position): #Takes a position we accidentally rounded into that is a block and hence has no node, returns a nearby node that isn't. #Since we do this for a lot of points, this is built to only check the height for all but problem points. i = int(position.x) j = int(position.y) count = 0 #If we have been passed a blocked point if instance.level.blockHeights[i][j] != 0: while instance.level.blockHeights[i][j] != 0: count += 1 if i > 40: i = i - 1 else: i = i + 1 if j > 25: j = j - 1 else: j = j + 1 #Assures no infinite loops if somehow caught in a large square at 40, 25. if count == 10: count = 0 if i > 40: i = i - 10 else: i = i + 10 if j > 25: j = j - 10 else: j = j + 10 position = Vector2(i, j) return position
def drawLevel(self): visible = QtGui.QImage(88, 50, QtGui.QImage.Format_Mono) visible.fill(0) if self.mouse: w = Wave((88, 50), lambda x, y: self.level.blocks.pixel(x, y) != 4294967295, lambda x, y: visible.setPixel(x, y, 1)) w.compute( Vector2( float(self.mouse.x()) / 10.0, float(self.mouse.y()) / 10.0)) for i, j in itertools.product(range(88), range(50)): color = self.level.blocks.pixel(i, j) if visible.pixel(i, j) != 4278190080: self.drawPixel((i, j), QtGui.qRgb(192, 0, 192)) else: self.drawPixel((i, j), color) colors = [QtGui.QColor(255, 0, 0), QtGui.QColor(32, 32, 255)] for i, (x, y) in enumerate(self.level.bases): self.drawBox((x - 2, y - 2), colors[i], 5, 'B') for i, (x, y) in enumerate(self.level.goals): self.drawBox((x - 1, y - 1), colors[i].darker(125), 3, 'G') for i, (x, y) in enumerate(self.level.flags): self.drawBox((x - 1, y - 1), colors[i].lighter(125), 3, 'F')
def get_view_command(self, command): bot = self.game.team.members[int(command.botId[-1])] final_direction = command.target[-1] influence_vector = Vector2(0, 0) total_count = 0.0 for node_index in self.graph.nodes(): p_enemy = self.graph.node[node_index]["p_enemy"] if p_enemy != 0.0: node_vector = regressions2.get_node_vector(self, node_index) influence_vector += node_vector / ( node_vector.distance(bot.position) + 1) * p_enemy total_count += 1 / (node_vector.distance(bot.position) + 1) * p_enemy if influence_vector.length() != 0.0: influence_vector /= total_count final_direction = influence_vector if type(command) == commands.Attack: command.lookAt = final_direction elif type(command) == commands.Defend: final_direction = final_direction - bot_position final_direction.normalize() command.facingDirection = final_direction return command
def get_direction(instance, enemy_bot): #TODO have this account for potentially changing directions. direction = None if enemy_bot.health == 0 or None: #See if bot has respawned since it was killed. respawned_time = get_respawn(instance, enemy_bot) #If the bot respawned, is about to respawn, or has state_unknown, assume it is in its spawn and facing the closest of our bots. if respawned_time != None or instance.game.match.timeToNextRespawn < 2.00 or enemy_bot.state == 0: spawn_position = Vector2.midPoint( instance.game.enemyTeam.botSpawnArea[0], instance.game.enemyTeam.botSpawnArea[1]) our_bot_positions = [ bot.position for bot in instance.game.team.members ] closest = float("inf") closest_point = None for position in our_bot_positions: distance = (position - spawn_position).length() if distance < closest: closest_point = position closest = distance direction = closest_point - spawn_position else: #Enemy is dead and hasn't respawned, return no probability for look directions. return None #If the enemy bot is alive, use its last known orientation to figure out where it is aiming. else: direction = enemy_bot.facingDirection return direction
def get_direction(instance, enemy_bot): #TODO have this account for potentially changing directions. direction = None if enemy_bot.health == 0 or None: #See if bot has respawned since it was killed. respawned_time = get_respawn(instance, enemy_bot) #If the bot respawned, is about to respawn, or has state_unknown, assume it is in its spawn and facing the closest of our bots. if respawned_time != None or instance.game.match.timeToNextRespawn < 2.00 or enemy_bot.state == 0: spawn_position = Vector2.midPoint(instance.game.enemyTeam.botSpawnArea[0], instance.game.enemyTeam.botSpawnArea[1]) our_bot_positions = [bot.position for bot in instance.game.team.members] closest = float("inf") closest_point = None for position in our_bot_positions: distance = (position - spawn_position).length() if distance < closest: closest_point = position closest = distance direction = closest_point - spawn_position else: #Enemy is dead and hasn't respawned, return no probability for look directions. return None #If the enemy bot is alive, use its last known orientation to figure out where it is aiming. else: direction = enemy_bot.facingDirection return direction
def one_bot_visibility(instance, bot): position = bot.position cells = [] w = visibility.Wave((88, 50), lambda x, y: instance.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x, y))) w.compute(position) instance.bots[bot.name]["visibility"] = set([get_node_index(instance, Vector2(x, y)) for x, y in cells]) return cells
def weight_camp_locations_by_sight(instance, close_nodes): #Calculate the weight of all squares close to the enemy base relying on how many of the exit squares can be shot. enemy_base = get_enemy_base(instance) for node_index in close_nodes: node_position = regressions2.get_node_vector(instance, node_index) cells = [] w = visibility.Wave((88, 50), lambda x, y: instance.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x, y))) w.compute(node_position) for x, y in cells: cell_position = Vector2(x, y) cell_node_index = regressions2.get_node_index( instance, cell_position) if node_position.distance( cell_position) < instance.level.firingDistance: #Edges don't work with our functions, and are unlikely to be actual optimum. #TODO fully debug rather than hack. if not (node_position.x < 1.0 or node_position.x > 87.0 or node_position.y < 1.0 or node_position.y > 47.0): camp_value = instance.graph.node[cell_node_index][ "camp_target"] / (cell_position.distance(enemy_base) + 3) instance.graph.node[node_index][ "camp_location"] += camp_value
def calculate_control_main_route2(instance): #Set ambush dictionary. for node_index in instance.graph.nodes(): instance.graph.node[node_index]["ambush"] = 0.0 start, finish = instance.level.botSpawnAreas[instance.game.enemyTeam.name] instance.graph.add_node("enemy_base", position = (start.x, start.y), weight = 0.0) instance.graph.node["enemy_base"]["ambush"] = 0.0 for i, j in itertools.product(range(int(start.x), int(finish.x)), range(int(start.y), int(finish.y))): instance.graph.add_edge("enemy_base", instance.terrain[j][i], weight = 1.0) our_flag_node = get_node_index(instance, instance.game.team.flag.position) enemy_score_node = get_node_index(instance, instance.game.enemyTeam.flagScoreLocation) enemy_flag_node = None vb2f = nx.shortest_path(instance.graph, source="enemy_base", target=our_flag_node) vf2s = nx.shortest_path(instance.graph, source=our_flag_node, target=enemy_score_node) path = vb2f + vf2s edgesinpath=zip(path[0:],path[1:]) for vt, vf in edgesinpath[:-1]: if "position" not in instance.graph.node[vf]: continue position = Vector2(*instance.graph.node[vf]["position"]) if "position" not in instance.graph.node[vt]: continue next_position = Vector2(*instance.graph.node[vt]["position"]) if position == next_position: continue orientation = (next_position - position).normalized() def visible(p): delta = (p-position) l = delta.length() if l < instance.level.firingDistance: return True else: return False cells = [] w = visibility.Wave((88, 50), lambda x, y: instance.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x,y))) w.compute(position) for x, y in [c for c in cells if visible(Vector2(c[0]+0.5, c[1]+0.5))]: instance.graph.node[get_node_index(instance, Vector2(x,y))]["ambush"] += 2.0
def get_camp_command(instance, bot, command): #Get view direction intended to optimize enemy choke in sight. Calc total choke in sight. Return. if len(instance.bots[bot.name]["visibility"]) > 0.0: cells = instance.bots[bot.name]["visibility"] else: cells = regressions2.one_bot_visibility(instance, bot) #LEFT OFF - USE TO SCORE CHOKE POINTS master_chokes = instance.master_chokes.intersection(cells) choke_dict = instance.choke_dict nodes = [node for node in master_chokes] if len(nodes) == 0: nodes = [node for node in choke_dict.keys()] first_node = nodes.pop() x, y = instance.graph.node[node]["position"] cell_position = Vector2(x, y) total_mass = 0.0 mass = instance.graph.node[first_node]["camp_target"] total_mass += mass center = mass * cell_position for cell_node in nodes: main_group_node = get_choke_group(instance, cell_node) #Weight nodes that are already targeted as less attractive to look at. if main_group_node != None: redundancy = choke_dict[main_group_node]["redundancy"] + 1 else: redundancy = 1.0 x, y = instance.graph.node[cell_node]["position"] cell_position = Vector2(x, y) mass = instance.graph.node[cell_node]["camp_target"] / (redundancy * 10) if cell_position.distance( bot.position) > instance.level.firingDistance or mass == 0.0: continue center += cell_position * mass total_mass += mass if total_mass != 0.0: final_vector = center / total_mass look_vector = final_vector - bot.position #Using description to store power of defend command. command.facingDirection = look_vector return command
def remove_spawn_nodes(instance, close_nodes): start, finish = instance.level.botSpawnAreas[instance.game.enemyTeam.name] for i, j in itertools.product(range(int(start.x), int(finish.x)), range(int(start.y), int(finish.y))): node_index = regressions2.get_node_index(instance, Vector2(i, j)) if node_index in close_nodes: close_nodes.remove(node_index) return close_nodes
def defenseTick(self, bot): if not (Vector2.distance(bot.position,self.game.team.flagSpawnLocation) > self.level.firingDistance and self.attackCloseEnemy(bot)): if len(self.closeVisibleLivingEnemies(bot)) > 1: for defender in self.myDefenders: if not self.visibleLivingEnemies(defender) and defender.state == defender.STATE_DEFENDING and self.lastCommand[defender] != 'doubling up': dir = [bot.facingDirection,defender.facingDirection] self.issueAndStore(commands.Defend, defender, dir, description = 'doubling up') if len(self.myAttackers) < 2 and len(self.myDefenders) > self.numEnemies and not bot.seenBy: self.goAttack(bot)
def calculatePOIS(points = []): results = points if points == None: for x in range(2): p = instance.level.findRandomFreePositionInBox(instance.level.area) o = Vector2(random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5)).normalized() results.append(p) instance.ambushes = [] instance.ambushes = results
def put_exit_paths_in_graph(instance, exit_paths): enemy_base = get_enemy_base(instance) for path, weight in exit_paths: edgesinpath = zip(path[0:], path[1:]) for vt, vf in edgesinpath[:-1]: if "position" not in instance.graph.node[vf]: continue position = Vector2(*instance.graph.node[vf]["position"]) if "position" not in instance.graph.node[vt]: continue next_position = Vector2(*instance.graph.node[vt]["position"]) if position == next_position: continue x = position.x y = position.y instance.graph.node[regressions2.get_node_index( instance, Vector2(x, y))]["exit_path"] += 5.0 * weight / ( position.distance(enemy_base)**3 + 1) instance.graph.node["enemy_base"]["exit_path"] = 0.0
def get_node_vector(instance, node_index): try: position = instance.graph.node[node_index]["position"] except: print "POSITION BUG... OFFENDING INDEX: ", node_index print instance.graph.node[node_index] position = instance.game.enemyTeam.flag.position x = position[0] y = position[1] return Vector2(x , y)
def weight_camp_locations_by_base_exposure(instance): #Adjust the weight based on what squares can be seen from the enemy base. start, finish = instance.level.botSpawnAreas[instance.game.enemyTeam.name] for i, j in itertools.product(range(int(start.x), int(finish.x)), range(int(start.y), int(finish.y))): enemy_base_square = Vector2(i, j) cells = [] w = visibility.Wave((88, 50), lambda x, y: instance.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x, y))) w.compute(enemy_base_square) for x, y in cells: cell_position = Vector2(x, y) cell_node_index = regressions2.get_node_index( instance, cell_position) if cell_position.distance( enemy_base_square) < instance.level.firingDistance + 3: instance.graph.node[cell_node_index]["camp_location"] *= .8 instance.graph.node["enemy_base"]["camp_location"] = 0.0
def get_path(instance, start, destination): #Deal with various node bugs. start_i, start_j = sanitize_position(instance, start) dest_i, dest_j = sanitize_position(instance, destination) start = Vector2(start_i, start_j) destination = Vector2(dest_i, dest_j) #Get the node index. start_node = get_node_index(instance, start) destination_node = get_node_index(instance, destination) try: path = nx.shortest_path(instance.graph, source = start_node, target = destination_node, weight = "weight") except: print "PATHING BUG, TARGET INDEX ERROR" path = nx.shortest_path(instance.graph, source = start_node, target = get_node_index(instance, instance.game.enemyTeam.flag.position), weight = "weight") #Convert list of node indexes to list of vectors for those nodes. for path_index in range(len(path)): node_index = path[path_index] node_vector = get_node_vector(instance, node_index) path[path_index] = node_vector return path
def resetDefenders(self): if self.cheating: return False if all(Vector2.distance(self.closestEnemy(x).position,x.position) >self.level.firingDistance*1.6 for x in self.myDefenders if self.closestEnemy(x) is not None): self.resetDefendDirections() for defender in self.myDefenders: if (self.defendPosition - defender.position).length() <= 2: dir = self.defendDirections[0] self.defendDirections.append(self.defendDirections.pop(0)) self.issueAndStore(commands.Defend, defender, dir, description = 'defend flag') return True return False
def one_bot_sees(instance, bot, simulated_bot = None): nodes = [] #finds visible squares to one bot, or a dictionary with keys "direction" and "position" if simulated_bot is specified. if not simulated_bot: cells = one_bot_visibility(instance, bot) for cell in cells: x = cell[0] y = cell[1] #Deals with problem of 1 height blocks being visible but not in path graph. if instance.level.blockHeights[x][y] == 1.0: continue cell_position = Vector2(x, y) if can_bot_see(instance, bot, cell_position): node_index = get_node_index(instance, cell_position) nodes.append(node_index) #This is for when we are looking at visibility points along a path as opposed to for a specific bot. The lack of DRY is bad, #but not backbreaking. #TODO refactor when free time allows. else: position = simulated_bot["position"] direction = simulated_bot["direction"] cells = [] w = visibility.Wave((88, 50), lambda x, y: instance.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x, y))) w.compute(position) for cell in cells: x = cell[0] y = cell[1] #Deals with problem of 1 height blocks being visible but not in path graph. if instance.level.blockHeights[x][y] == 1.0: continue cell_position = Vector2(x, y) position_to_bot_vector = cell_position - position angle = get_angle(direction, position_to_bot_vector) bot_fov = instance.level.fieldOfViewAngles[bot.state] if not bot_fov: bot_fov = 1.57 if abs(angle) < bot_fov/2.0: node_index = get_node_index(instance, cell_position) nodes.append(node_index) return nodes
def initialSetup(self): self.defenders = {} bots = self.game.bots_alive for i, bot in enumerate(sorted(bots, key=lambda x: distanceBetween(x, self.game.team.flag))): if len(self.defenders.values()) < self.numOfDefWanted: j = len(self.defenders.values()) if j%2 == 0: self.defenders[j] = Bot(bot) else: self.defenders[j] = Bot(bot, defending_direction=Vector2(0, 1)) else: self.attackers.add(Bot(bot)) self.currState = self.STATE_NEUTRAL
def initialize(self): self.attacker = Team([], self) self.defender = Team([], self) self.waitingBots = Team(self.game.team.members, self) self.verbose = True # Calculate flag positions and store the middle. ours = self.game.team.flag.position theirs = self.game.enemyTeam.flag.position spawnArea = self.game.team.botSpawnArea self.middle = (theirs + ours) / 2.0 # Now figure out the flaking directions, assumed perpendicular. d = (ours - theirs) self.left = Vector2(-d.y, d.x).normalized() self.right = Vector2(d.y, -d.x).normalized() self.front = Vector2(d.x, d.y).normalized() #initialize the telemetry class that keeps track of data. self.logger = telemetry.LogTelemetry("tstlog.log") # initialize the wait time for after defending. self.defenseWait = 4
def get_at_large_enemies(instance, known_enemies): #List enemies without 100% certainty of location. #Format is bot, last known position. unknown_enemies = [] for enemy_bot in instance.game.enemyTeam.members: if enemy_bot not in known_enemies and enemy_bot not in unknown_enemies: if enemy_bot.seenlast == None: time_seen = 0.0 position = Vector2.midPoint(instance.game.enemyTeam.botSpawnArea[0], instance.game.enemyTeam.botSpawnArea[1]) else: time_seen = instance.game.match.timePassed - enemy_bot.seenlast position = enemy_bot.position unknown_enemies.append([enemy_bot, position, time_seen]) return unknown_enemies
def sanitize_position(instance, position): #Takes a position we accidentally rounded into that is a block and hence has no node, returns a nearby node that isn't. #Since we do this for a lot of points, this is built to only check the height for all but problem points. i = int(position.x) j = int(position.y) #Deal with flying off map; I.E. through extrapolation. if i > 87.0: print "ALTERING X TO BE ON MAP" i = 87 if i < 0.0: i = 1 print "ALTERING X TO BE ON MAP" if j < 0.0: j = 0 print "ALTERING Y TO BE ON MAP" if j > 49.0: j = 49 print "ALTERING Y TO BE ON MAP" count = 0 #If we have been passed a blocked point if instance.level.blockHeights[i][j] != 0: while instance.level.blockHeights[i][j] != 0: count += 1 if i > 40: i = i-1 else: i = i+1 if j > 25: j = j-1 else: j = j+1 #Assures no infinite loops if somehow caught in a large square at 40, 25. if count % 10 == 0: count = 0 if i > 40: i = i-3 else: i = i+3 if j > 25: j = j-3 else: j = j+3 #Deal with 0 node bug. if i == 0 and j == 0: i += 10 j += 10 i, j = sanitize_position(instance, Vector2(i,j)) return (i, j)
def account_for_spawns(instance, at_large_enemies): #Updates positions of enemies whose health is ostensibly 0 based on if they have respawned. #Dead enemies that have respawned still appear as health 0, and are very much a threat! for enemy_info in at_large_enemies: if enemy_info[0].health == 0 or None: #See if bot has respawned since it was killed. respawned_time = get_respawn(instance, enemy_info[0]) #If the bot respawned figure count its last seen as the center of its respawn. if respawned_time != None: enemy_spawn_coord = Vector2.midPoint( instance.game.enemyTeam.botSpawnArea[0], instance.game.enemyTeam.botSpawnArea[1]) enemy_info[1] = enemy_spawn_coord enemy_info[ 2] = instance.game.match.timePassed - respawned_time + .5 #If the bot is respawning in the next two seconds, count its last seen as the center of its respawn. elif instance.game.match.timeToNextRespawn < 2.00: enemy_spawn_coord = Vector2.midPoint( instance.game.enemyTeam.botSpawnArea[0], instance.game.enemyTeam.botSpawnArea[1]) enemy_info[1] = enemy_spawn_coord enemy_info[2] = 2.0 #If the game has just begun and the bot is chilling in his spawn, assign him as there. #TODO better spawn positioning. elif enemy_info[0].state == 0: enemy_spawn_coord = Vector2.midPoint( instance.game.enemyTeam.botSpawnArea[0], instance.game.enemyTeam.botSpawnArea[1]) enemy_info[1] = enemy_spawn_coord enemy_info[ 2] = -1.5 #This is a hack so that we evaluate enemy bots as present at the start. It works pretty well. #If none of the above are true, the bot is dead and we don't need to worry about him. else: at_large_enemies.remove(enemy_info) ## print at_large_enemies return at_large_enemies
def weight_camp_locations_by_choke_exposure(instance): for node in instance.choke_dict.keys(): enemy_base_square = regressions2.get_node_vector(instance, node) cells = [] w = visibility.Wave((88, 50), lambda x, y: instance.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x, y))) w.compute(enemy_base_square) for x, y in cells: cell_position = Vector2(x, y) cell_node_index = regressions2.get_node_index( instance, cell_position) if cell_position.distance( enemy_base_square) < instance.level.firingDistance + 3: instance.graph.node[cell_node_index]["camp_location"] *= .8
def get_at_large_enemies(instance, known_enemies): #List enemies without 100% certainty of location. #Format is bot, last known position. unknown_enemies = [] for enemy_bot in instance.game.enemyTeam.members: if enemy_bot not in known_enemies and enemy_bot not in unknown_enemies: if enemy_bot.seenlast == None: time_seen = 0.0 position = Vector2.midPoint( instance.game.enemyTeam.botSpawnArea[0], instance.game.enemyTeam.botSpawnArea[1]) else: time_seen = instance.game.match.timePassed - enemy_bot.seenlast position = enemy_bot.position unknown_enemies.append([enemy_bot, position, time_seen]) return unknown_enemies
def getLookDirectionArray(self, numActions, command): """Returns an arbitrary length list of commands based on the passed command with random look directions.""" newActionList = [] if type(command) == commands.Attack: for x in range(numActions): direction = self.level.findRandomFreePositionInBox( self.level.area) command.lookAt = direction newActionList.append(command) elif type(command) == commands.Defend: for x in range(numActions): direction = Vector2( random.random() * random.sample([-1, 1], 1)[0], random.random() * random.sample([-1, 1], 1)[0]) command.facingDirection = direction newActionList.append(command) return newActionList
def update_visibility_graph(instance): #Turn all cells currently seen by enemies to 1 in graph. for bot in instance.game.enemyTeam.members: if bot.seenlast < 2.0 and bot.health > 0.0: cells = one_bot_visibility(instance, bot) for cell in cells: cell_position = Vector2(cell[0], cell[1]) index = getNodeIndex(instance, cell_position) if can_bot_shoot(instance, bot, cell_position): change_node(instance, index, 1.0) for edge in instance.graph.edges(): #Is the destination of the edge visible to enemies? #Set all edges with visible destinations to weight 1.0. if instance.graph.node[edge[1]]["weight"] == 1.0: instance.graph.edge[edge[0]][edge[1]]["weight"] = 1.0 else: instance.graph.edge[edge[0]][edge[1]]["weight"] = .05
class DefendingGroup(): VectorOne = (Vector2(1.55, 1), 1) VectorTwo = (Vector2(-1.55, 1), 1) VectorThree = (Vector2(0, -1), 1) VectorFour = (Vector2(0, 1), 1) VectorFive = (Vector2(1.55, -1), 1) VectorSix = (Vector2(-1.55, -1), 1) Vectors = [ VectorOne, VectorTwo, VectorThree, VectorFour, VectorFour, VectorFive, VectorSix ] def assignVector(self, isCorner): if (isCorner == (0, 0)): return elif (isCorner == (1, 0)): self.Vectors = [(Vector2(1, 0), 1), (Vector2(1, 1.55), 1), (Vector2(1, -1.55), 1)] elif (isCorner == (-1, 0)): self.Vectors = [(Vector2(-1, 0), 1), (Vector2(-1, 1.55), 1), (Vector2(-1, -1.55), 1)] elif (isCorner == (0, 1)): self.Vectors = [(Vector2(0, 1), 1), (Vector2(1.55, 1), 1), (Vector2(-1.55, 1), 1)] elif (isCorner == (0, -1)): self.Vectors = [(Vector2(0, -1), 1), (Vector2(1.55, -1), 1), (Vector2(-1.55, -1), 1)] elif (isCorner == (1, 1)): self.Vectors = [(Vector2(1.55, 1), 1), (Vector2(1, 1.55), 1)] elif (isCorner == (1, -1)): self.Vectors = [(Vector2(1.55, -1), 1), (Vector2(1, -1.55), 1)] elif (isCorner == (-1, 1)): self.Vectors = [(Vector2(-1.55, 1), 1), (Vector2(-1, 1.55), 1)] elif (isCorner == (-1, -1)): self.Vectors = [(Vector2(-1.55, -1), 1), (Vector2(-1, -1.55), 1)] def __init__(self, bots, isCorner=(0, 0)): self.assignVector(isCorner) self.defenders = {} self.assignDefenders(bots) def assignDefenders(self, defenders): if not defenders: return splitVectors = list(chunks(self.Vectors, len(defenders))) for i, bot in enumerate(defenders): self.defenders[bot] = splitVectors[i] def reAssignRoles(self): aliveDefenders = filter(lambda x: x.health > 0, self.defenders.keys()) self.assignDefenders(aliveDefenders) for bot in aliveDefenders: bot.defenceTrigger = 1
def closestDefender(self, enemy): closest = min(self.myDefenders, key=lambda x:Vector2.distance(x.position,enemy.position)) return closest
def closestEnemy(self, bot): closest = None visibleLivingEnemies = self.visibleLivingEnemies(bot) if visibleLivingEnemies: closest = min(visibleLivingEnemies, key=lambda x:Vector2.distance(bot.position,x.position)) return closest
def maximizeLineOfSite(self, vect1, vect2): if type(vect2) == type((1,2)): vect2 = vect2[0] dot = vect1.dotProduct(vect2) return math.acos(dot/(Vector2.length(vect1) + Vector2.length(vect2)))
def enemyJustOutsideRange(self, bot): closestEnemy = self.closestEnemy(bot) if not closestEnemy == None: if Vector2.distance(bot.position, closestEnemy.position) < self.level.firingDistance + self.level.firingDistance/4: return closestEnemy return None
def enemyInRange(self, bot): for enemy in self.visibleLivingEnemies(bot): enemyDistance = Vector2.distance(bot.position, enemy.position) if(enemyDistance <= self.level.firingDistance): return True return False