示例#1
0
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
示例#2
0
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