class Agent(object): """Class handles all command and control logic for a teams tanks.""" def __init__(self, bzrc): self.bzrc = bzrc self.constants = self.bzrc.get_constants() self.commands = [] self.ALPHA = 0.01 self.BETA = 0.3 self.OBS_TOLERANCE = 35.0 self.S = 50 self.wroteonce = False self.goalradius = 30 self.tankradius = 5 self.avoidradius = 50 self.avoidBETA = 0.05 self.aimtolerance = math.pi/20 self.world_grid = WorldGrid() self.bayes = Bayes() self.turnprob = 0.05 self.turndecisionprob = 0.5 self.turned = False self.turniter = 0 self.TURN_MAX = 50 self.OCCUPIED = 1; self.UNOCCUPIED = 0; def tick(self, time_diff): """Some time has passed; decide what to do next.""" mytanks, othertanks, flags, shots = self.bzrc.get_lots_o_stuff() self.mytanks = mytanks self.othertanks = othertanks self.flags = [flag for flag in flags if flag.color != self.constants['team']] self.shots = shots self.enemies = [tank for tank in othertanks if tank.color != self.constants['team']] #self.obstacles = self.bzrc.get_obstacles() self.commands = [] for tank in mytanks: pos, grid = self.bzrc.get_occgrid(tank.index) self.update_priors(pos, grid) self.world_grid.draw_obstacle_grid() for tank in mytanks: self.goto_closest_target(tank) results = self.bzrc.do_commands(self.commands) def update_priors(self, position, grid): for x in range(len(grid)): for y in range(len(grid[x])): prior = self.world_grid.get_world_value(x, y, position) observation = grid[x][y] if observation == self.OCCUPIED: new_prior = self.bayes.probability_occupied_given_observed(prior) else: new_prior = self.bayes.probability_occupied_given_not_observed(prior) self.world_grid.set_world_value(x, y, position, new_prior) def move(self, mytanks): # it's not turning, so decide to turn or go straight if self.turned == False and self.turniter == 0: rand = random.random() # returns a number [0, 1) if rand < self.turnprob: for tank in mytanks: self.turn(tank) self.turned = True else: for tank in mytanks: self.go_straight(tank) else: # it is turning self.turniter = self.turniter + 1 if self.turniter >= self.TURN_MAX: self.turned = False self.turniter = 0 def turn(self, tank): rand = random.random() # returns a number [0, 1) if rand < self.turndecisionprob: command = Command(tank.index, 1, 1, False) # turn right self.commands.append(command) else: command = Command(tank.index, 0.5, -1, False) # turn left self.commands.append(command) def go_straight(self, tank): command = Command(tank.index, 1, 0, False) self.commands.append(command) def get_my_base(self): mybases = [base for base in self.bzrc.get_bases() if base.color == self.constants['team']] mybase = mybases[0] return mybase def get_base_center(self, base): center_x = ((base.corner1_x + base.corner2_x + base.corner3_x + base.corner4_x) / 4) center_y = ((base.corner1_y + base.corner2_y + base.corner3_y + base.corner4_y) / 4) return center_x, center_y def goto_closest_target(self, tank): best_tar = self.get_best_target(tank.x, tank.y) if best_tar is None: command = Command(tank.index, 0, 0, False) self.commands.append(command) else: print "Tank :", tank.x, tank.y print "Target: ", best_tar self.move_to_position(tank, best_tar[0], best_tar[1]) def get_best_target(self, x, y): best_tar = None best_dist = 2 * float(self.constants['worldsize']) for tar in self.world_grid.getTargetLocations(): dist = math.sqrt((tar[0] - x)**2 + (tar[1] - y)**2) if dist < best_dist: best_dist = dist best_tar = tar return best_tar def goto_flags(self, tank): best_flag = self.get_best_flag(tank.x, tank.y) if best_flag is None: command = Command(tank.index, 0, 0, False) self.commands.append(command) else: self.move_to_position(tank, best_flag.x, best_flag.y) def get_best_flag(self, x, y): best_flag = None best_dist = 2 * float(self.constants['worldsize']) for flag in self.flags: dist = math.sqrt((flag.x - x)**2 + (flag.y - y)**2) if dist < best_dist: best_dist = dist best_flag = flag return best_flag def avoid_target(self, my_x, my_y, target_x, target_y): goal_dist = math.sqrt((target_x - my_x)**2 + (target_y - my_y)**2) target_angle = math.atan2(target_y - my_y, target_x - my_x) dx = 0 dy = 0 s = self.avoidradius r = self.tankradius if goal_dist < self.tankradius: dx = -1 * math.cos(target_angle) * 1000 #infinity dy = -1 * math.sin(target_angle) * 1000 #infinity elif goal_dist >= self.tankradius and goal_dist <= (s + r): dx = -1 * self.avoidBETA * (s + r - goal_dist) * math.cos(target_angle) dy = -1 * self.avoidBETA * (s + r - goal_dist) * math.sin(target_angle) else: dx = 0 dy = 0 return dx, dy def calculate_enemies_delta(self, my_x, my_y, enemies): delta_x = 0 delta_y = 0 for tank in enemies: dx, dy = self.avoid_target(my_x, my_y, tank.x, tank.y) delta_x += dx delta_y += dy sqnorm = math.sqrt(delta_x**2 + delta_y**2) if sqnorm == 0: delta_x = 0 delta_y = 0 else: delta_x = delta_x / sqnorm delta_y = delta_y / sqnorm return delta_x, delta_y def calculate_objective_delta(self, my_x, my_y, target_x, target_y): goal_dist = math.sqrt((target_x - my_x)**2 + (target_y - my_y)**2) target_angle = math.atan2(target_y - my_y, target_x - my_x) delta_xG = self.ALPHA * goal_dist * math.cos(target_angle) # r = 0 delta_yG = self.ALPHA * goal_dist * math.sin(target_angle) # r = 0 sqnorm = math.sqrt(delta_xG**2 + delta_yG**2) #set magnitude magnitude = 0 if goal_dist > self.goalradius: magnitude = 1 else: magnitude = sqnorm if sqnorm == 0: delta_xG = 0 delta_yG = 0 else: delta_xG = delta_xG / sqnorm delta_yG = delta_yG / sqnorm return delta_xG, delta_yG, magnitude """def calculate_obstacles_delta(self, x, y): delta_xO = 0 delta_yO = 0 for obs in self.obstacles: repel_xO, repel_yO = self.get_obstacle_force(obs, x, y) delta_xO += repel_xO delta_yO += repel_yO sqnorm = math.sqrt(delta_xO**2 + delta_yO**2) if sqnorm == 0: delta_xO = 0 delta_yO = 0 else: delta_xO = delta_xO / sqnorm delta_yO = delta_yO / sqnorm '''if delta_xG != 0 or delta_yG != 0: print "delta_xO: ", delta_xO print "delta_yO: ", delta_yO''' return delta_xO, delta_yO""" def calculate_random_delta(self): dx = random.uniform(-.01, .01) dy = random.uniform(-.01, .01) return dx, dy def should_fire(self, tank): for enemy in self.enemies: target_angle = math.atan2(enemy.y - tank.y, enemy.x - tank.x) if abs(tank.angle - target_angle) < self.aimtolerance: return True return False def move_to_position(self, tank, target_x, target_y): """Set command to move to given coordinates.""" #get deltas delta_xG, delta_yG, magnitude = self.calculate_objective_delta(tank.x, tank.y, target_x, target_y) #delta_xO, delta_yO = self.calculate_obstacles_delta(tank.x, tank.y) delta_xO, delta_yO = 0, 0 delta_xR, delta_yR = self.calculate_random_delta() #delta_xA, delta_yA = self.calculate_enemies_delta(tank.x, tank.y, self.enemies) #combine delta_x = delta_xG + delta_xO + delta_xR #+ delta_xA delta_y = delta_yG + delta_yO + delta_yR #+ delta_xA #calculate angle turn_angle = math.atan2(delta_y, delta_x) relative_angle = self.normalize_angle(turn_angle - tank.angle) #put lower bound on speed: no slower than 40% if magnitude < 0.4: magnitude = 0.4 fire = self.should_fire(tank) command = Command(tank.index, magnitude, 2 * relative_angle, False) self.commands.append(command) def get_obstacle_force(self, obstacle, x, y): delta_x = 0 delta_y = 0 big_num = 5000 min_x = big_num max_x = -big_num min_y = big_num max_y = -big_num for p in obstacle: repel_x, repel_y = self.get_tangential_field(x, y, p) delta_x += repel_x delta_y += repel_y xp, yp = p if xp < min_x: min_x = xp elif xp > max_x: max_x = xp if yp < min_y: min_y = yp elif yp > max_y: max_y = yp center_point = [(min_x + min_y) / 2, (min_y + max_y) / 2] repel_x, repel_y = self.get_repel_field(x, y, center_point[0], center_point[1]) # repel from the center of the box delta_x += repel_x delta_y += repel_y return delta_x, delta_y def get_tangential_field(self, x, y, p): my_x = x my_y = y xO, yO = p dist = math.sqrt( (my_x - xO)**2 + (my_y - yO)**2 ) if dist < self.OBS_TOLERANCE: # angle between the tank and the obstacle theta = math.atan2(yO - y, xO - x) + math.pi / 2 delta_x = -self.BETA * (self.avoidradius - dist) * math.cos(theta) delta_y = -self.BETA * (self.avoidradius - dist) * math.sin(theta) return delta_x, delta_y else: return 0, 0 def get_repel_field(self, x, y, xO, yO): my_x = x my_y = y dist = math.sqrt( (my_x - xO)**2 + (my_y - yO)**2 ) if dist < self.OBS_TOLERANCE: # angle between the tank and the obstacle theta = math.atan2(yO - y, xO - x) delta_x = -self.BETA * (self.avoidradius - dist) * math.cos(theta) # math.cos returns in radians delta_y = -self.BETA * (self.avoidradius - dist) * math.sin(theta) return delta_x, delta_y else: return 0, 0 def normalize_angle(self, angle): """Make any angle be between +/- pi.""" angle -= 2 * math.pi * int (angle / (2 * math.pi)) if angle <= -math.pi: angle += 2 * math.pi elif angle > math.pi: angle -= 2 * math.pi return angle
class Agent(object): """Class handles all command and control logic for a teams tanks.""" def __init__(self, bzrc): self.bzrc = bzrc self.constants = self.bzrc.get_constants() self.commands = [] self.ALPHA = 0.01 self.BETA = 0.3 self.OBS_TOLERANCE = 35.0 self.S = 50 self.wroteonce = False self.goalradius = 30 self.tankradius = 5 self.avoidradius = 50 self.avoidBETA = 0.05 self.aimtolerance = math.pi / 20 self.world_grid = WorldGrid() self.bayes = Bayes() self.turnprob = 0.05 self.turndecisionprob = 0.5 self.turned = False self.turniter = 0 self.TURN_MAX = 50 self.OCCUPIED = 1 self.UNOCCUPIED = 0 def tick(self, time_diff): """Some time has passed; decide what to do next.""" mytanks, othertanks, flags, shots = self.bzrc.get_lots_o_stuff() self.mytanks = mytanks self.othertanks = othertanks self.flags = [ flag for flag in flags if flag.color != self.constants['team'] ] self.shots = shots self.enemies = [ tank for tank in othertanks if tank.color != self.constants['team'] ] #self.obstacles = self.bzrc.get_obstacles() self.commands = [] for tank in mytanks: pos, grid = self.bzrc.get_occgrid(tank.index) self.update_priors(pos, grid) self.world_grid.draw_obstacle_grid() for tank in mytanks: self.goto_closest_target(tank) results = self.bzrc.do_commands(self.commands) def update_priors(self, position, grid): for x in range(len(grid)): for y in range(len(grid[x])): prior = self.world_grid.get_world_value(x, y, position) observation = grid[x][y] if observation == self.OCCUPIED: new_prior = self.bayes.probability_occupied_given_observed( prior) else: new_prior = self.bayes.probability_occupied_given_not_observed( prior) self.world_grid.set_world_value(x, y, position, new_prior) def move(self, mytanks): # it's not turning, so decide to turn or go straight if self.turned == False and self.turniter == 0: rand = random.random() # returns a number [0, 1) if rand < self.turnprob: for tank in mytanks: self.turn(tank) self.turned = True else: for tank in mytanks: self.go_straight(tank) else: # it is turning self.turniter = self.turniter + 1 if self.turniter >= self.TURN_MAX: self.turned = False self.turniter = 0 def turn(self, tank): rand = random.random() # returns a number [0, 1) if rand < self.turndecisionprob: command = Command(tank.index, 1, 1, False) # turn right self.commands.append(command) else: command = Command(tank.index, 0.5, -1, False) # turn left self.commands.append(command) def go_straight(self, tank): command = Command(tank.index, 1, 0, False) self.commands.append(command) def get_my_base(self): mybases = [ base for base in self.bzrc.get_bases() if base.color == self.constants['team'] ] mybase = mybases[0] return mybase def get_base_center(self, base): center_x = ((base.corner1_x + base.corner2_x + base.corner3_x + base.corner4_x) / 4) center_y = ((base.corner1_y + base.corner2_y + base.corner3_y + base.corner4_y) / 4) return center_x, center_y def goto_closest_target(self, tank): best_tar = self.get_best_target(tank.x, tank.y) if best_tar is None: command = Command(tank.index, 0, 0, False) self.commands.append(command) else: print "Tank :", tank.x, tank.y print "Target: ", best_tar self.move_to_position(tank, best_tar[0], best_tar[1]) def get_best_target(self, x, y): best_tar = None best_dist = 2 * float(self.constants['worldsize']) for tar in self.world_grid.getTargetLocations(): dist = math.sqrt((tar[0] - x)**2 + (tar[1] - y)**2) if dist < best_dist: best_dist = dist best_tar = tar return best_tar def goto_flags(self, tank): best_flag = self.get_best_flag(tank.x, tank.y) if best_flag is None: command = Command(tank.index, 0, 0, False) self.commands.append(command) else: self.move_to_position(tank, best_flag.x, best_flag.y) def get_best_flag(self, x, y): best_flag = None best_dist = 2 * float(self.constants['worldsize']) for flag in self.flags: dist = math.sqrt((flag.x - x)**2 + (flag.y - y)**2) if dist < best_dist: best_dist = dist best_flag = flag return best_flag def avoid_target(self, my_x, my_y, target_x, target_y): goal_dist = math.sqrt((target_x - my_x)**2 + (target_y - my_y)**2) target_angle = math.atan2(target_y - my_y, target_x - my_x) dx = 0 dy = 0 s = self.avoidradius r = self.tankradius if goal_dist < self.tankradius: dx = -1 * math.cos(target_angle) * 1000 #infinity dy = -1 * math.sin(target_angle) * 1000 #infinity elif goal_dist >= self.tankradius and goal_dist <= (s + r): dx = -1 * self.avoidBETA * (s + r - goal_dist) * math.cos(target_angle) dy = -1 * self.avoidBETA * (s + r - goal_dist) * math.sin(target_angle) else: dx = 0 dy = 0 return dx, dy def calculate_enemies_delta(self, my_x, my_y, enemies): delta_x = 0 delta_y = 0 for tank in enemies: dx, dy = self.avoid_target(my_x, my_y, tank.x, tank.y) delta_x += dx delta_y += dy sqnorm = math.sqrt(delta_x**2 + delta_y**2) if sqnorm == 0: delta_x = 0 delta_y = 0 else: delta_x = delta_x / sqnorm delta_y = delta_y / sqnorm return delta_x, delta_y def calculate_objective_delta(self, my_x, my_y, target_x, target_y): goal_dist = math.sqrt((target_x - my_x)**2 + (target_y - my_y)**2) target_angle = math.atan2(target_y - my_y, target_x - my_x) delta_xG = self.ALPHA * goal_dist * math.cos(target_angle) # r = 0 delta_yG = self.ALPHA * goal_dist * math.sin(target_angle) # r = 0 sqnorm = math.sqrt(delta_xG**2 + delta_yG**2) #set magnitude magnitude = 0 if goal_dist > self.goalradius: magnitude = 1 else: magnitude = sqnorm if sqnorm == 0: delta_xG = 0 delta_yG = 0 else: delta_xG = delta_xG / sqnorm delta_yG = delta_yG / sqnorm return delta_xG, delta_yG, magnitude """def calculate_obstacles_delta(self, x, y): delta_xO = 0 delta_yO = 0 for obs in self.obstacles: repel_xO, repel_yO = self.get_obstacle_force(obs, x, y) delta_xO += repel_xO delta_yO += repel_yO sqnorm = math.sqrt(delta_xO**2 + delta_yO**2) if sqnorm == 0: delta_xO = 0 delta_yO = 0 else: delta_xO = delta_xO / sqnorm delta_yO = delta_yO / sqnorm '''if delta_xG != 0 or delta_yG != 0: print "delta_xO: ", delta_xO print "delta_yO: ", delta_yO''' return delta_xO, delta_yO""" def calculate_random_delta(self): dx = random.uniform(-.01, .01) dy = random.uniform(-.01, .01) return dx, dy def should_fire(self, tank): for enemy in self.enemies: target_angle = math.atan2(enemy.y - tank.y, enemy.x - tank.x) if abs(tank.angle - target_angle) < self.aimtolerance: return True return False def move_to_position(self, tank, target_x, target_y): """Set command to move to given coordinates.""" #get deltas delta_xG, delta_yG, magnitude = self.calculate_objective_delta( tank.x, tank.y, target_x, target_y) #delta_xO, delta_yO = self.calculate_obstacles_delta(tank.x, tank.y) delta_xO, delta_yO = 0, 0 delta_xR, delta_yR = self.calculate_random_delta() #delta_xA, delta_yA = self.calculate_enemies_delta(tank.x, tank.y, self.enemies) #combine delta_x = delta_xG + delta_xO + delta_xR #+ delta_xA delta_y = delta_yG + delta_yO + delta_yR #+ delta_xA #calculate angle turn_angle = math.atan2(delta_y, delta_x) relative_angle = self.normalize_angle(turn_angle - tank.angle) #put lower bound on speed: no slower than 40% if magnitude < 0.4: magnitude = 0.4 fire = self.should_fire(tank) command = Command(tank.index, magnitude, 2 * relative_angle, False) self.commands.append(command) def get_obstacle_force(self, obstacle, x, y): delta_x = 0 delta_y = 0 big_num = 5000 min_x = big_num max_x = -big_num min_y = big_num max_y = -big_num for p in obstacle: repel_x, repel_y = self.get_tangential_field(x, y, p) delta_x += repel_x delta_y += repel_y xp, yp = p if xp < min_x: min_x = xp elif xp > max_x: max_x = xp if yp < min_y: min_y = yp elif yp > max_y: max_y = yp center_point = [(min_x + min_y) / 2, (min_y + max_y) / 2] repel_x, repel_y = self.get_repel_field( x, y, center_point[0], center_point[1]) # repel from the center of the box delta_x += repel_x delta_y += repel_y return delta_x, delta_y def get_tangential_field(self, x, y, p): my_x = x my_y = y xO, yO = p dist = math.sqrt((my_x - xO)**2 + (my_y - yO)**2) if dist < self.OBS_TOLERANCE: # angle between the tank and the obstacle theta = math.atan2(yO - y, xO - x) + math.pi / 2 delta_x = -self.BETA * (self.avoidradius - dist) * math.cos(theta) delta_y = -self.BETA * (self.avoidradius - dist) * math.sin(theta) return delta_x, delta_y else: return 0, 0 def get_repel_field(self, x, y, xO, yO): my_x = x my_y = y dist = math.sqrt((my_x - xO)**2 + (my_y - yO)**2) if dist < self.OBS_TOLERANCE: # angle between the tank and the obstacle theta = math.atan2(yO - y, xO - x) delta_x = -self.BETA * (self.avoidradius - dist) * math.cos( theta) # math.cos returns in radians delta_y = -self.BETA * (self.avoidradius - dist) * math.sin(theta) return delta_x, delta_y else: return 0, 0 def normalize_angle(self, angle): """Make any angle be between +/- pi.""" angle -= 2 * math.pi * int(angle / (2 * math.pi)) if angle <= -math.pi: angle += 2 * math.pi elif angle > math.pi: angle -= 2 * math.pi return angle