def followRightWall(unit, map): if unit.id not in currentDirections: currentDirections[unit.id] = goToWall(unit, map) (x, y) = apply_direction(unit.x, unit.y, currentDirections[unit.id].value) if((x<0 or y<0 or x>=len(map[0]) or y >= len(map)) and (currentDirections[unit.id].value % 2)==0): currentDirections[unit.id] = Direction((currentDirections[unit.id].value - 2) % 8) i = 2 (x, y) = apply_direction(unit.x, unit.y, (currentDirections[unit.id].value + i) % 8) direction = Direction((currentDirections[unit.id].value + i) % 8) # starts at direction right to current direction # and checks if it as a valid location to move to # then sequentially points counter-clockwise until a valid direction is found while(x<0 or y<0 or x>=len(map[0]) or y >= len(map) or map[y][x]!=0): i -= 1 direction = Direction((currentDirections[unit.id].value + i) % 8) (x, y) = apply_direction(unit.x, unit.y, direction.value) # update current facing direction and return direction to move currentDirections[unit.id] = direction return direction
def isAtWall(unit, map): (x, y) = apply_direction(unit.x, unit.y, Direction.NORTH.value) if(x<0 or y<0 or x>=len(map[0]) or y >= len(map)): return True (x, y) = apply_direction(unit.x, unit.y, Direction.EAST.value) if(x<0 or y<0 or x>=len(map[0]) or y >= len(map)): return True (x, y) = apply_direction(unit.x, unit.y, Direction.SOUTH.value) if(x<0 or y<0 or x>=len(map[0]) or y >= len(map)): return True (x, y) = apply_direction(unit.x, unit.y, Direction.WEST.value) if(x<0 or y<0 or x>=len(map[0]) or y >= len(map)): return True return False
def chooseRandom(unit, map): direction = Direction.STILL (x, y) = (unit.x, unit.y) # keep choosing a random direction until the direction is legal # also prevents unit from standing still while(direction==Direction.STILL or x<0 or y<0 or x>=len(map[0]) or y >= len(map) or map[y][x]!=0): direction = random.choice(list(Direction)) (x, y) = apply_direction(unit.x, unit.y, direction.value) return direction
def isSufficientlySurrounded(unit, map): surroundingObstacles = 0 for direction in Direction: if(direction==Direction.STILL): continue (x, y) = apply_direction(unit.x, unit.y, direction.value) if(x<0 or y<0 or x>=len(map[0]) or y >= len(map) or map[y][x]==1): surroundingObstacles += 1 if(surroundingObstacles >= 6): return True else: return False
def goToWall(unit, map): # gets closest point to the closest wall (targetx, targety) = getClosestWall(unit, map) # a Dictionary to keep track of possible directions to move possibleDirections = {} for direction in Direction: (x, y) = apply_direction(unit.x, unit.y, direction.value) #discount illegal directions if(direction==Direction.STILL or x<0 or y<0 or x>=len(map[0]) or y >= len(map) or map[y][x]!=0): pass # map distances to each direction else: possibleDirections[direction] = getDistance(x, y, targetx, targety) # return direction that is shortest return min(possibleDirections, key=possibleDirections.get)
def chooseAntDirection(unit, map): if unit.id not in currentDirections: currentDirections[unit.id] = Direction.STILL (x, y) = apply_direction(unit.x, unit.y, currentDirections[unit.id].value) # if unit hits a wall or has no assigned direction if(currentDirections[unit.id]==Direction.STILL or x<0 or y<0 or x>=len(map[0]) or y >= len(map) or map[y][x]!=0): # assign a random direction for it currentDirections[unit.id] = chooseRandom(unit, map) direction = currentDirections[unit.id] # otherwise, continue in its current direction else: direction = currentDirections[unit.id] return direction
def antiGreedy(current, enemy, map): bestDirection = None farthestDistance = 0 # for each possible direction, figure out its distance to the target for direction in Direction: (x, y) = apply_direction(current.x, current.y, direction.value) # if direction is still or not legal, continue with the loop if(direction==Direction.STILL or x<0 or y<0 or x>=len(map[0]) or y >= len(map) or map[y][x]!=0): continue # figure out the farthest distance distance = getDistance(x, y, enemy.x, enemy.y) if (distance > farthestDistance): bestDirection = direction farthestDistance = distance # return the best direction return bestDirection
def greedy(current, target, map): bestDirection = None closestDistance = math.inf # for each possible direction, figure out its distance to the target for direction in Direction: (x, y) = apply_direction(current.x, current.y, direction.value) # if direction is still or not legal, continue with the loop if(direction==Direction.STILL or x<0 or y<0 or x>=len(map[0]) or y >= len(map) or map[y][x]!=0): continue # figure out the shortest distance distance = getDistance(x, y, target.x, target.y) if (distance < closestDistance): bestDirection = direction closestDistance = distance # return the best direction return bestDirection
def handle(agent: Agent, commands: list): for _, unit in enumerate(agent.units): game_map = agent.map # the map # unit.id is id of the unit # unit.x unit.y are its coordinates, unit.distance is distance away from nearest opponent # game_map is the 2D map of what you can see. # game_map[i][j] returns whats on that tile, 0 = empty, 1 = wall, # anything else is then the id of a unit which can be yours or the opponents # get direction from a human controller myDirection = getdirectionvalue(unit, agent) # apply direction to current unit's position to check if that new position is on the game map (x, y) = apply_direction(unit.x, unit.y, myDirection) if (x < 0 or y < 0 or x >= len(game_map[0]) or y >= len(game_map)): # we do nothing if the new position is not in the map # TODO notify human and request to display 'Hit the wall' on the server pass else: commands.append(unit.move(myDirection))
if not reachedWall[unit.id]: direction = goToWall(unit, game_map) currentDirections[unit.id] = direction else: direction = followRightWall(unit, game_map) # if hiders seen, apply basic greedy alorithm to move closer to it else: reachedWall[unit.id] = False closestEnemy = opposingUnits[0] direction = greedy(unit, closestEnemy, game_map) currentDirections[unit.id] = direction # apply direction to current unit's position to check if that new position is on the game map (x, y) = apply_direction(unit.x, unit.y, direction.value) if (x < 0 or y < 0 or x >= len(game_map[0]) or y >= len(game_map)): # we do nothing if the new position is not in the map pass else: commands.append(unit.move(direction.value)) index += 1 else: index = 0 # index is depracated for _, unit in enumerate(units): # to keep track of units that need to get to the wall initally if unit.id not in reachedWall: reachedWall[unit.id] = False if (not reachedWall[unit.id]) and isAtWall(unit, game_map):
if (agent.team == Team.SEEKER): # AI Code for seeker goes here for _, unit in enumerate(units): # unit.id is id of the unit # unit.x unit.y are its coordinates, unit.distance is distance away from nearest opponent # game_map is the 2D map of what you can see. # game_map[i][j] returns whats on that tile, 0 = empty, 1 = wall, # anything else is then the id of a unit which can be yours or the opponents # choose a random direction to move in randomDirection = random.choice(list(Direction)).value # apply direction to current unit's position to check if that new position is on the game map (x, y) = apply_direction(unit.x, unit.y, randomDirection) if (x < 0 or y < 0 or x >= len(game_map[0]) or y >= len(game_map)): # we do nothing if the new position is not in the map pass else: commands.append(unit.move(randomDirection)) else: # AI Code for hider goes here # hider code, which does nothing, sits tight and hopes it doesn't get # found by seekers pass # submit commands to the engine print(','.join(commands))
def main(logs): global seed def log(msg, unitid=None, level='INFO'): if level == 'DEBUG' and not verbose: return for flog in logs: identity = agent.team.name if unitid == None else '{} {}'.format( agent.team.name, unitid) flog.write('{} [{}] <{}>: {}\n'.format(time.asctime(), level, identity, msg)) flog.flush() def vlog(*args, **kwargs): # if verbose: log(*args, **kwargs, level='DEBUG') if seed == None: seed = random.getrandbits(32) random.seed(seed) log('Competition started with team seed: {}'.format(seed)) agent.init_log(log, len(logs) > 0) agent.post_log_init() while True: vlog('Round #{}/200 begins'.format(agent.round_num)) commands = [] units = agent.units # list of units you own opposingUnits = agent.opposingUnits # list of units on other team that you can see # game_map = agent.map # the map round_num = agent.round_num # the round number vlog('Visible opponent ids: {}'.format( list(map(lambda unit: unit.id, opposingUnits)))) agent.opponents_update() if need_human: human.handle(agent, commands) else: if agent.team == Team.SEEKER: # AI Code for seeker goes here # for _, unit in enumerate(units): for unit in units: def ulog(*args, **kwargs): log(*args, **kwargs, unitid=unit.id) def uvlog(*args, **kwargs): vlog(*args, **kwargs, unitid=unit.id) # unit.id is id of the unit # unit.x unit.y are its coordinates, unit.distance is distance away from nearest opponent # game_map is the 2D map of what you can see. # game_map[i][j] returns whats on that tile, 0 = empty, 1 = wall, # anything else is then the id of a unit which can be yours or the opponents uvlog('Location: {}. R^2 distance to closest opponent {}.'. format((unit.x, unit.y), unit.distance)) # # choose a random direction to move in # myDirection = random.choice(list(Direction)).value # # apply direction to current unit's position to check if that new position is on the game map # (x, y) = apply_direction(unit.x, unit.y, myDirection) # if (x < 0 or y < 0 or x >= len(game_map[0]) or y >= len(game_map)): # # we do nothing if the new position is not in the map # pass # else: # commands.append(unit.move(myDirection)) closest_dist = math.inf lowest_uncertainty = math.inf best_moves = [] # Do nothing and stay still # primary_target = False # target has primary location, usually in sight # dead_hider_ids = [] for op in mod_op.opponents.values(): # lastloc = op.get_primary_loc() lastloc = op.lastseen if lastloc != None: goto = lastloc else: # goto = random.choice() # FIXME for seed reasons goto = op.possible_list[0] # ulog('FIXME: no primary locations!', level='WARN') # pass # FIXME use more advanced pathing (Ex. sweep search) in this case uncertainty = op.location_count opx, opy = goto try: nxdir, dist = agent.pathing( unit.x, unit.y, opx, opy) uvlog('Distance to opponent {}: {}'.format( op.id, dist)) assert len(nxdir) > 0 if dist <= 1: ulog( "Hider {} should be dead and shouldn't be on the stage!" .format(op.id), level='WARN') # dead_hider_ids.append(op.id) else: if (uncertainty, dist) < (lowest_uncertainty, closest_dist): closest_dist = dist lowest_uncertainty = uncertainty if op.primary_loc != None: uvlog( 'Greedily selecting next move from {} by distance' .format(list(map(Direction, nxdir)))) bestmv = None r2distbest = math.inf for candidate in nxdir: cdist = vision.distance_squared( *apply_direction( unit.x, unit.y, candidate), opx, opy) if cdist < r2distbest: r2distbest = cdist bestmv = candidate best_moves = [bestmv] else: best_moves = nxdir except NoPath: ulog('No path to hider ID {}'.format(op.id)) # for dead_hider_id in dead_hider_ids: # del opponents[dead_hider_id] if len(best_moves) == 0: if opponents: ulog('No best next move!', level='WARN') else: uvlog('Possible next moves: {}'.format( list(map(Direction, best_moves)))) my_move = random.choice(best_moves) uvlog('Actually moving toward: {}'.format( Direction(my_move))) commands.append(unit.move(my_move)) if not opponents: log('No opponents left') else: # AI Code for hider goes here # hider code, which does nothing, sits tight and hopes it doesn't get # found by seekers if debug: agent.debug_distance_map(agent.seeker_map) for unit in units: def ulog(*args, **kwargs): log(*args, **kwargs, unitid=unit.id) def uvlog(*args, **kwargs): vlog(*args, **kwargs, unitid=unit.id) myinfo = unit.get_info() hider_state = myinfo.hider_state if hider_state == HiderState.FRESH: loop_candidates = set() viable_target_cells = [] my_distance_map = agent.generate_distance_map([ (unit.x, unit.y) ]) for y in range(agent.ydim): for x in range(agent.xdim): if my_distance_map[y][ x] != math.inf and my_distance_map[y][ x] + 2 <= agent.seeker_map[y][x]: for loop in agent.loop_index[y][x]: viable_target_cells.append((x, y)) loop_candidates.add(loop) ulog('Viable loops: {}'.format( list( map( lambda loop: ((loop.x0, loop.y0), (loop.x1, loop.y1)), loop_candidates)))) if len(loop_candidates) == 0: ulog('Unable to find a viable loop!', level='WARN') else: for other in units: otherinfo = other.get_info() if len(loop_candidates) > 1: if other is not unit and otherinfo.hider_loop != None and otherinfo.hider_loop in loop_candidates: loop_candidates.remove( otherinfo.hider_loop) else: break hider_loop: Loop = random.choice( list(loop_candidates)) myinfo.hider_loop = hider_loop ulog('Chosen loop: {} to {}'.format( (hider_loop.x0, hider_loop.y0), (hider_loop.x1, hider_loop.y1))) # for px, py in hider_loop.cell_set: for px, py in viable_target_cells: for other in units: if other.get_info().hiding_target == (px, py): break else: myinfo.hiding_target = (px, py) break assert myinfo.hiding_target != None ulog('Chosen hiding target {}'.format( myinfo.hiding_target)) if myinfo.hiding_target == None: hidex, hidey = viable_target_cells[0] ulog( 'Have to share hiding target with another unit all @ {}!' .format((hidex, hidey)), level='ERROR') myinfo.hiding_target = (hidex, hidey) ulog('Chosen hiding target: {}'.format( myinfo.hiding_target)) hider_state = HiderState.HIDING elif hider_state == HiderState.HIDING: nxdir, dist = agent.pathing(unit.x, unit.y, myinfo.hiding_target[0], myinfo.hiding_target[1]) if dist == 0: hider_state = HiderState.CIRCLING ulog('Entered circling state') else: chosendir = random.choice(nxdir) uvlog('Moving with direction {} toward {} to hide'. format(Direction(chosendir), myinfo.hiding_target)) commands.append(unit.move(chosendir)) if hider_state == HiderState.CIRCLING: uvlog('Circling: seeker distance here: {}'.format( agent.seeker_map[unit.y][unit.x])) maxdist = agent.seeker_map[unit.y][ unit.x] # Not moving take precedence mdmove = 8 # Greedily choose the lowest distance for dirnum, (dx, dy) in enumerate(kit.direction_deltas): nx = unit.x + dx ny = unit.y + dy if agent.walkable(nx, ny) and ( nx, ny) in myinfo.hider_loop.cell_set: newdist = agent.seeker_map[ny][nx] if newdist >= maxdist: mdmove = dirnum maxdist = newdist uvlog( 'Moving toward {} for greatest seeker distance {}'. format(Direction(mdmove), maxdist)) commands.append(unit.move(mdmove)) unit.get_info().hider_state = hider_state # vlog('Submitting commands...') # submit commands to the engine print(','.join(commands)) # vlog('Sending end turn command...') # now we end our turn agent.end_turn() vlog('Round ended. Waiting for updates from engine...') # wait for update from match engine agent.update() vlog('Updated bot based on response from engine.')