def execute_running(self): super().execute_running() # abort if we can't see the ball if not main.ball().valid: return ball_pos = main.ball().pos self.intercept = (constants.Field.OurGoalSegment.center() - main.ball().pos) * 0.25 + main.ball().pos # the closest of their bots to the ball is their kicker their_kicker = min(main.their_robots(), key=lambda opp: opp.pos.dist_to(ball_pos)) # we build an array of OpponentRobots sorted rudimentarily by their threat # Right now, this is (inverse of) distance to the ball * 2 + y position. # Needs tuning/improvement. Right now this is excessively defensive sorted_opponents = sorted( filter(lambda robot: robot != their_kicker, main.their_robots()), key=lambda robot: self.calculate_shot_chance(robot), reverse=True) # Decide what each marking robot should do # @sorted_opponents contains the robots we want to mark by priority # any robot that isn't assigned a mark_robot will move towards the ball for i, mark_i in enumerate(self.marks): if i < len(sorted_opponents): mark_i.mark_robot = sorted_opponents[i] self.marks[2].mark_robot = their_kicker self.marks[2].mark_ratio = 0.5
def execute_running(self): super().execute_running() # abort if we can't see the ball if not main.ball().valid: return ball_pos = main.ball().pos # the closest of their bots to the ball is their kicker their_kicker = min(main.their_robots(), key=lambda opp: opp.pos.dist_to(ball_pos)) # we build an array of OpponentRobots sorted rudimentarily by their threat # Right now, this is (inverse of) distance to the ball * 2 + y position. # Needs tuning/improvement. Right now this is excessively defensive sorted_opponents = sorted( filter(lambda robot: robot != their_kicker, main.their_robots()), key=lambda robot: robot.pos.dist_to(ball_pos) * 2 + robot.pos.y) # Decide what each marking robot should do # @sorted_opponents contains the robots we want to mark by priority # any robot that isn't assigned a mark_robot will move towards the ball for i, mark_i in enumerate(self.marks): if i < len(sorted_opponents): mark_i.mark_robot = sorted_opponents[i]
def execute_running(self): # abort if we can't see the ball if not main.ball().valid: return ball_pos = main.ball().pos # the closest of their bots to the ball is their kicker their_kicker = min(main.their_robots(), key=lambda opp: opp.pos.dist_to(ball_pos)) # we build an array of (OpponentRobot, float distToClosestOfOurBots) tuples # we'll use these in a sec to assign our marking robots open_opps_and_dists = [] for opp in main.their_robots(): # ignore their kicker if opp == their_kicker: continue ball_dist = opp.pos.dist_to(ball_pos) # see if the opponent is close enough to the ball for us to care # if it is, we record the closest distance from one of our robots to it if ball_dist < 3.0: # which of our robots is closest to this opponent closest_self_dist = min([bot.pos.dist_to(opp.pos) for bot in main.our_robots()]) open_opps_and_dists.append( (opp, closest_self_dist) ) # Decide what each marking robot should do # @open_opps contains the robots we want to mark (if any) # any robot that isn't assigned a mark_robot will move towards the ball for i, mark_i in enumerate(self.marks): if mark_i.robot != None: if i < len(open_opps_and_dists): # mark the opponent mark_i.mark_robot = open_opps_and_dists[i][0] else: pass # NOTE: the old code ran these motion commands INSTEAD of running the mark command # we could do that, but it'd require removing the subbehavior and re-adding a move or something... # # move towards the ball and face it, but don't get within field center's radius # pos = mark_i.robot.pos # target = pos + (ball_pos - pos).normalized() * (ball_pos.dist_to(pos) - constants.Field.CenterRadius) # mark_i.robot.move(target) # mark_i.face(ball_pos) # tell the marking robots to avoid eachother more than normal for i, mark_i in enumerate(self.marks): for j, mark_j in enumerate(self.marks): if i == j: continue if mark_i.robot != None and mark_j.robot != None: mark_i.robot.set_avoid_teammate_radius(mark_j.robot.shell_id(), 0.5)
def execute_running(self): super().execute_running() # abort if we can't see the ball if not main.ball().valid: return ball_pos = main.ball().pos # the closest of their bots to the ball is their kicker their_kicker = min(main.their_robots(), key=lambda opp: opp.pos.dist_to(ball_pos)) # we build an array of (OpponentRobot, float distToClosestOfOurBots) tuples # we'll use these in a sec to assign our marking robots open_opps_and_dists = [] for opp in main.their_robots(): # ignore their kicker if opp == their_kicker: continue ball_dist = opp.pos.dist_to(ball_pos) # see if the opponent is close enough to the ball for us to care # if it is, we record the closest distance from one of our robots to it if ball_dist < 3.0: # which of our robots is closest to this opponent closest_self_dist = min( [bot.pos.dist_to(opp.pos) for bot in main.our_robots()]) open_opps_and_dists.append((opp, closest_self_dist)) # Decide what each marking robot should do # @open_opps contains the robots we want to mark (if any) # any robot that isn't assigned a mark_robot will move towards the ball for i, mark_i in enumerate(self.marks): if mark_i.robot != None: if i < len(open_opps_and_dists): # mark the opponent mark_i.mark_robot = open_opps_and_dists[i][0] else: pass # NOTE: the old code ran these motion commands INSTEAD of running the mark command # we could do that, but it'd require removing the subbehavior and re-adding a move or something... # # move towards the ball and face it, but don't get within field center's radius # pos = mark_i.robot.pos # target = pos + (ball_pos - pos).normalized() * (ball_pos.dist_to(pos) - constants.Field.CenterRadius) # mark_i.robot.move(target) # mark_i.face(ball_pos) # tell the marking robots to avoid eachother more than normal for i, mark_i in enumerate(self.marks): for j, mark_j in enumerate(self.marks): if i == j: continue if mark_i.robot != None and mark_j.robot != None: mark_i.robot.set_avoid_teammate_radius( mark_j.robot.shell_id(), 0.5)
def can_collect_ball_before_opponent(our_robots_to_check=None, their_robots_to_check=None, our_robots_to_dodge=None, their_robots_to_dodge=None, valid_error_percent=0.05): if our_robots_to_check is None: our_robots_to_check = main.our_robots() if their_robots_to_check is None: their_robots_to_check = main.their_robots() if our_robots_to_dodge is None: our_robots_to_dodge = main.our_robots() if their_robots_to_dodge is None: their_robots_to_dodge = main.their_robots() shortest_opp_time = float("inf") shortest_our_time = float("inf") dodge_dist = constants.Robot.Radius closest_robot = None # TODO: Do some sort of prediction as the ball moves target_pos = main.ball().pos # TODO: Take velocity and acceleration into account # Find closest opponent robot for bot in their_robots_to_check: dist = estimate_path_length(bot.pos, target_pos, our_robots_to_dodge, dodge_dist) target_dir = (target_pos - bot.pos).normalized() time = robocup.get_trapezoidal_time( dist, dist, 2.2, 1, target_dir.dot(bot.vel) / target_dir.mag(), 0) if (time < shortest_opp_time): shortest_opp_time = time # Find closest robot on our team for bot in our_robots_to_check: dist = estimate_path_length(bot.pos, target_pos, their_robots_to_dodge, dodge_dist) target_dir = (target_pos - bot.pos).normalized() time = robocup.get_trapezoidal_time( dist, dist, 2.2, 1, target_dir.dot(bot.vel) / target_dir.mag(), 0) if (time < shortest_our_time): shortest_our_time = time closest_robot = bot # Greater than 1 when we are further away print(shortest_our_time) print(shortest_opp_time) return shortest_our_time < shortest_opp_time * ( 1 + valid_error_percent), closest_robot
def can_collect_ball_before_opponent(our_robots_to_check=None, their_robots_to_check=None, our_robots_to_dodge=None, their_robots_to_dodge=None, valid_error_percent=0.05): if our_robots_to_check is None: our_robots_to_check = main.our_robots() if their_robots_to_check is None: their_robots_to_check = main.their_robots() if our_robots_to_dodge is None: our_robots_to_dodge = main.our_robots() if their_robots_to_dodge is None: their_robots_to_dodge = main.their_robots() shortest_opp_time = float("inf") shortest_our_time = float("inf") dodge_dist = constants.Robot.Radius closest_robot = None # TODO: Do some sort of prediction as the ball moves target_pos = main.ball().pos # TODO: Take velocity and acceleration into account # Find closest opponent robot for bot in their_robots_to_check: dist = estimate_path_length(bot.pos, target_pos, our_robots_to_dodge, dodge_dist) target_dir = (target_pos - bot.pos).normalized() time = robocup.get_trapezoidal_time(dist, dist, 2.2, 1, target_dir.dot(bot.vel) / target_dir.mag(), 0) if (time < shortest_opp_time): shortest_opp_time = time # Find closest robot on our team for bot in our_robots_to_check: dist = estimate_path_length(bot.pos, target_pos, their_robots_to_dodge, dodge_dist) target_dir = (target_pos - bot.pos).normalized() time = robocup.get_trapezoidal_time(dist, dist, 2.2, 1, target_dir.dot(bot.vel) / target_dir.mag(), 0) if (time < shortest_our_time): shortest_our_time = time closest_robot = bot return shortest_our_time < shortest_opp_time * (1 + valid_error_percent ), closest_robot
def num_on_offense(): # Complementary filter based on... # Distance to their goal # Distance to the ball goal_loc = robocup.Point(0, constants.Field.Length) corner_loc = robocup.Point(constants.Field.Width / 2, 0) ball_loc = main.ball().pos max_goal_dis = (goal_loc - corner_loc).mag() ball_to_goal = (goal_loc - ball_loc).mag() offense_ctr = 0 filter_coeff = 0.7 score_cutoff = .3 # For each of their robots for bot in main.their_robots(): if bot.visible: dist_to_ball = (bot.pos - ball_loc).mag() dist_to_goal = (bot.pos - goal_loc).mag() goal_coeff = dist_to_goal / max_goal_dis if ball_to_goal != 0: ball_coeff = 1 - (dist_to_ball / ball_to_goal) else: ball_coeff = 1 ball_coeff = max(0, ball_coeff * ball_coeff) score = filter_coeff * goal_coeff + (1 - filter_coeff) * ball_coeff # Only count if their score is above the cutoff if (score > score_cutoff): offense_ctr += 1 return offense_ctr
def is_goalie_close(self): # if any of there robots are in near chip range chip over them close_check = False for r in main.their_robots(): close_check = close_check or ( r.pos - main.ball().pos).mag() < self.goalie_range return close_check
def in_chip_distance(self): chipIndicator = False for r in main.their_robots(): chipIndicator = chipIndicator or ( r.pos - constants.Field.OurGoalSegment.nearest_point( r.pos)).mag() < self.chip_distance return chipIndicator
def other_robot_touching_ball(self): max_radius = constants.Robot.Radius + constants.Ball.Radius + 0.03 for bot in list(main.our_robots()) + list(main.their_robots()): if bot.visible and (not bot.is_ours() or not bot.shell_id() == self.kicker_shell_id): if bot.pos.near_point(main.ball().pos, max_radius): return True return False
def other_robot_touching_ball(self): for bot in filter(lambda bot: bot.visible, list(main.our_robots()) + list(main.their_robots())): if (bot.is_ours() and bot.has_ball() and bot.shell_id() != self.kicker_shell_id): return True if ((bot.shell_id() != self.kicker_shell_id or not bot.is_ours()) and self._bot_in_radius(bot)): return True return False
def find_defense_positions(ignore_robots=[]): their_risk_scores = [] for bot in main.their_robots(): score = estimate_risk_score(bot.pos, ignore_robots) main.system_state().draw_text("Risk: " + str(int(score * 100)), bot.pos, constants.Colors.White, "Defense") their_risk_scores.extend([score]) # Sorts bot array based on their score zipped_array = zip(their_risk_scores, main.their_robots()) sorted_array = sorted(zipped_array, reverse=True) sorted_bot = [bot for (scores, bot) in sorted_array] area_def_pos = create_area_defense_zones(ignore_robots) return area_def_pos, sorted_bot[0], sorted_bot[1]
def find_defense_positions(ignore_robots=[]): their_risk_scores = [] for bot in main.their_robots(): score = estimate_risk_score(bot.pos, ignore_robots) main.debug_drawer().draw_text("Risk: " + str(int(score * 100)), bot.pos, constants.Colors.White, "Defense") their_risk_scores.extend([score]) # Sorts bot array based on their score zipped_array = zip(their_risk_scores, main.their_robots()) sorted_array = sorted(zipped_array, reverse=True) sorted_bot = [bot for (scores, bot) in sorted_array] area_def_pos = create_area_defense_zones(ignore_robots) return area_def_pos, sorted_bot[0], sorted_bot[1]
def execute_setup_penalty(self): pt = robocup.Point(0, robocup.Field_PenaltyDist) penalty_kicker = min(main.their_robots(), key=lambda r: (r.pos - pt).mag()) angle_rad = penalty_kicker.angle shot_line = robocup.Line(penalty_kicker.pos, penalty_kicker.pos + robocup.Point.direction(angle_rad)) dest = shot_line.intersection(Goalie.RobotSegment) if dest == None: self.robot.move_to(robocup.Point(0, constants.Robot.Radius)) else: dest.x = max(-Goalie.MaxX + constants.Robot.Radius, dest.x) dest.y = min(Goalie.MaxX - constants.Robot.Radius, dest.x) self.robot.move_to(dest)
def execute_running(self): super().execute_running() # abort if we can't see the ball if not main.ball().valid: return ball_pos = main.ball().pos # the closest of their bots to the ball is their kicker their_kicker = min(main.their_robots(), key=lambda opp: opp.pos.dist_to(ball_pos)) # we build an array of (OpponentRobot, float distToClosestOfOurBots) tuples # we'll use these in a sec to assign our marking robots open_opps_and_dists = [] for opp in main.their_robots(): # ignore their kicker if opp == their_kicker: continue ball_dist = opp.pos.dist_to(ball_pos) # see if the opponent is close enough to the ball for us to care # if it is, we record the closest distance from one of our robots to it if ball_dist < 3.0: # which of our robots is closest to this opponent closest_self_dist = min( [bot.pos.dist_to(opp.pos) for bot in main.our_robots()]) open_opps_and_dists.append((opp, closest_self_dist)) # Decide what each marking robot should do # @open_opps contains the robots we want to mark (if any) # any robot that isn't assigned a mark_robot will move towards the ball for i, mark_i in enumerate(self.marks): if mark_i.robot != None: if i < len(open_opps_and_dists): # mark the opponent mark_i.mark_robot = open_opps_and_dists[i][0] else: pass
def execute_running(self): super().execute_running() # abort if we can't see the ball if not main.ball().valid: return ball_pos = main.ball().pos # the closest of their bots to the ball is their kicker their_kicker = min(main.their_robots(), key=lambda opp: opp.pos.dist_to(ball_pos)) # we build an array of (OpponentRobot, float distToClosestOfOurBots) tuples # we'll use these in a sec to assign our marking robots open_opps_and_dists = [] for opp in main.their_robots(): # ignore their kicker if opp == their_kicker: continue ball_dist = opp.pos.dist_to(ball_pos) # see if the opponent is close enough to the ball for us to care # if it is, we record the closest distance from one of our robots to it if ball_dist < 3.0: # which of our robots is closest to this opponent closest_self_dist = min([bot.pos.dist_to(opp.pos) for bot in main.our_robots()]) open_opps_and_dists.append((opp, closest_self_dist)) # Decide what each marking robot should do # @open_opps contains the robots we want to mark (if any) # any robot that isn't assigned a mark_robot will move towards the ball for i, mark_i in enumerate(self.marks): if mark_i.robot != None: if i < len(open_opps_and_dists): # mark the opponent mark_i.mark_robot = open_opps_and_dists[i][0] else: pass
def __init__(self): super().__init__(continuous=True) self.debug = False self.add_transition(behavior.Behavior.State.start, behavior.Behavior.State.running, lambda: True, 'immediately') self.marks = [] if (main.game_state().is_their_direct()): self.intercept = (constants.Field.OurGoalSegment.center() - main.ball().pos) * 0.25 + main.ball().pos self.add_subbehavior(skills.move.Move(self.intercept), 'intercept direct', required=False, priority=5) for i in range(3): mark_i = skills.mark.Mark() mark_i.ratio = 0.7 self.add_subbehavior(mark_i, 'mark' + str(i), required=False, priority=3 - i) self.marks.append(mark_i) self.kick_eval = robocup.KickEvaluator(main.system_state()) self.kick_eval.debug = True for i, robot in enumerate(main.our_robots()): self.kick_eval.add_excluded_robot(robot) for i, robot in enumerate(main.their_robots()): self.kick_eval.add_excluded_robot(robot) their_kicker = min(main.their_robots(), key=lambda opp: opp.pos.dist_to(main.ball().pos)) self.kick_eval.add_excluded_robot(their_kicker)
def within_range(self): shortest_opp_dist = 10 shortest_our_dist = 10 # TODO: Do some sort of prediction as the ball moves target_pos = main.ball().pos # Find closest opponent robot for bot in main.their_robots(): dist = self.estimate_path_length(bot.pos, target_pos, main.our_robots()) if (dist < shortest_opp_dist): shortest_opp_dist = dist # Find closest robot on our team for bot in main.our_robots(): dist = self.estimate_path_length(bot.pos, target_pos, main.their_robots()) if (dist < shortest_our_dist): shortest_our_dist = dist # Greater than 1 when we are further away return shortest_our_dist < shortest_opp_dist * 1.05
def opponent_with_ball(): closest_bot, closest_dist = None, float("inf") for bot in main.their_robots(): if bot.visible: dist = (bot.pos - main.ball().pos).mag() if dist < closest_dist: closest_bot, closest_dist = bot, dist if closest_bot == None: return None else: if robot_has_ball(closest_bot): return closest_bot else: return None
def execute_setup_penalty(self): pt = robocup.Point(0, robocup.Field_PenaltyDist) penalty_kicker = min(main.their_robots(), key=lambda r: (r.pos - pt).mag()) angle_rad = penalty_kicker.angle shot_line = robocup.Line( penalty_kicker.pos, penalty_kicker.pos + robocup.Point.direction(angle_rad)) dest = shot_line.intersection(Goalie.RobotSegment) if dest == None: self.robot.move_to(robocup.Point(0, constants.Robot.Radius)) else: dest.x = max(-Goalie.MaxX + constants.Robot.Radius, dest.x) dest.y = min(Goalie.MaxX - constants.Robot.Radius, dest.x) self.robot.move_to(dest)
def get_transition_point(self): segment = constants.Field.OurGoalSegment line = robocup.Line(main.ball().pos, main.their_robots()[0].pos) goalie_pos = constants.Field.OurGoalSegment.center() if (self.has_subbehavior_with_name('block')): block_robot = self.subbehavior_with_name('block').robot if (block_robot != None): goalie_pos = block_robot.pos #find the point that the robot is most likely going to shoot at goal_intercept = segment.line_intersection(line) #if robot is not lined up with the goal assume the bot will shoot center if goal_intercept == None: goal_intercept = segment.center() #get the vector of the ball to the ideal shot point ball_to_goal_intercept = goal_intercept - main.ball().pos #normalize the vector ball_to_goal_intercept = ball_to_goal_intercept.normalized() #the ideal spot to be will be the chip distance times the normalized vector from the ball's #current point. ideal_defence = ball_to_goal_intercept * self.chip_distance + main.ball( ).pos #find the line of the shot the robot will make ball_to_goal_segment = robocup.Segment(main.ball().pos, goal_intercept) #this is the point to get our robot to block the shot the quickest. fastest_defence = ball_to_goal_segment.nearest_point(goalie_pos) #if robot is blocking the shot already just go to the ideal point otherwise average the vectors #based on the blocking percentage. if (goalie_pos.dist_to(fastest_defence) < (constants.Robot.Radius / 4)): move_to_point = ideal_defence else: move_to_point = robocup.Point( (ideal_defence.x * (self.block_percentage)) + (fastest_defence.x * (1 - self.block_percentage)), ((ideal_defence.y * self.block_percentage) + fastest_defence.y * (1 - self.block_percentage))) return move_to_point
def get_closest_opponent(pos, direction_weight=0, excluded_robots=[]): closest_bot, closest_dist = None, float("inf") for bot in main.their_robots(): if bot.visible and bot not in excluded_robots: dist = (bot.pos - pos).mag() if (pos.y <= bot.pos.y): dist *= (2 - direction_weight / 2) else: dist *= (2 + direction_weight / 2) if dist < closest_dist: closest_bot = bot closest_dist = dist return closest_bot
def space_coeff_at_pos(pos, excluded_robots=[], robots=None): # TODO: Add in velocity prediction if robots == None: robots = main.their_robots() max_dist = robocup.Point(constants.Field.Width / 2, constants.Field.Length).mag() total = 0 sensitivity = 8 for bot in robots: if bot.visible and bot not in excluded_robots: u = sensitivity * (bot.pos - pos).mag() / max_dist # Use Triweight kernal function (Force to be positive) # Graph looks much like a normal distribution total += max((35 / 32) * pow((1 - pow(u, 2)), 3), 0) return min(total, 1)
def execute_setup_penalty(self): pt = robocup.Point(0, constants.Field.PenaltyDist) penalty_kicker = min(main.their_robots(), key=lambda r: (r.pos - pt).mag()) angle_rad = penalty_kicker.angle shot_line = robocup.Line( penalty_kicker.pos, penalty_kicker.pos + robocup.Point.direction(angle_rad)) dest = Goalie.RobotSegment.line_intersection(shot_line) if dest is None: self.robot.move_to( robocup.Point(0, constants.Robot.Radius + Goalie.OFFSET)) else: dest.x = max(-Goalie.MaxX + constants.Robot.Radius, dest.x) dest.x = min(Goalie.MaxX - constants.Robot.Radius, dest.x) # Shots don't follow the top threat, they follow the inverse # FIXME this is kind of a hack dest.x = -dest.x self.robot.move_to(dest)
def classify_opponent_robots(self): del self.wingers[:] del self.forwards[:] for bot in main.their_robots(): if bot.visible and bot.pos.y < constants.Field.Length / 2: robot_risk_score = self.calculate_robot_risk_scores(bot) area_risk_score = self.calculate_area_risk_scores(bot) features = [robot_risk_score, area_risk_score] is_wing, class_score = evaluation.linear_classification.binary_classification( features, WingerWall.WING_FORWARD_WEIGHTS, WingerWall.WING_FORWARD_BIAS, WingerWall.WING_FORWARD_CUTOFF) is_wing = not is_wing #appears tobe inverted fix TODO if is_wing: self.wingers.append((class_score, bot)) else: self.forwards.append((class_score, bot))
def opp_robot_blocking(self): if (self.robot is None): return False # Closest opp robot in any direction # To us, not the ball closest_opp_robot = None closest_opp_dist = float("inf") for r in main.their_robots(): if ((r.pos - self.robot.pos).mag() < closest_opp_dist): closest_opp_robot = r closest_opp_dist = (r.pos - self.robot.pos).mag() # Only do this if a robot is in range robot_in_range = closest_opp_dist < .2 + 2 * constants.Robot.Radius aim_dir = robocup.Point.direction(self.robot.angle) robot_dir = (closest_opp_robot.pos - self.robot.pos) # Only trigger if they are infront of us robot_in_front = aim_dir.dot(robot_dir) > 0 closest_pt = robocup.Line( self.robot.pos, self.robot.pos + aim_dir).nearest_point(closest_opp_robot.pos) does_hit_robot = (closest_opp_robot.pos - closest_pt ).mag() < constants.Robot.Radius facing_their_side = robocup.Point.direction(self.robot.angle).y > 0 ret = (facing_their_side and robot_in_range and robot_in_front and does_hit_robot) if ret: print("Panic kick") main.debug_drawer().draw_text('panic kick', self.robot.pos, (255, 255, 255), 'PivotKick') return ret
def execute_setup_penalty(self): if main.ball().valid: pt = main.ball().pos else: # FIXME is this correct? pt = robocup.Point(0, constants.Field.PenaltyLongDist) penalty_kicker = min(main.their_robots(), key=lambda r: (r.pos - pt).mag()) angle_rad = penalty_kicker.angle shot_line = robocup.Line( penalty_kicker.pos, penalty_kicker.pos + robocup.Point.direction(angle_rad)) dest = Goalie.RobotSegment.line_intersection(shot_line) if dest is None: self.robot.move_to( robocup.Point(0, constants.Robot.Radius + Goalie.OFFSET)) else: dest.x = max(-Goalie.MaxX + constants.Robot.Radius, dest.x) dest.x = min(Goalie.MaxX - constants.Robot.Radius, dest.x) # Shots don't follow the top threat, they follow the inverse # FIXME this is kind of a hack dest.x = -dest.x self.robot.move_to(dest)
def eval_pt_to_seg(self, origin, target): end = target.delta().magsq() # if target is a zero-length segment, there are no windows if end == 0: return [], None if self.debug: main.system_state().draw_line(target, constants.Colors.Blue, "Debug") windows = [Window(0, end)] # apply the obstacles bots = filter(lambda bot: bot not in self.excluded_robots and bot.visible, (list(main.our_robots()) + list(main.their_robots()))) bot_locations = list(map(lambda bot: bot.pos, bots)) bot_locations.extend(self.hypothetical_robot_locations) for pos in bot_locations: d = (pos - origin).mag() # whether or not we can chip over this bot chip_overable = (self.chip_enabled and (d < self.max_chip_range - constants.Robot.Radius) and (d > self.min_chip_range + constants.Robot.Radius)) if not chip_overable: self.obstacle_robot(windows, origin, target, pos) # set the segment and angles for each window p0 = target.get_pt(0) delta = target.delta() / end for w in windows: w.segment = robocup.Segment(p0 + delta * w.t0, p0 + delta * w.t1) w.a0 = (w.segment.get_pt(0) - origin).angle() * constants.RadiansToDegrees w.a1 = (w.segment.get_pt(1) - origin).angle() * constants.RadiansToDegrees best = max(windows, key=lambda w: w.segment.delta().magsq()) if len(windows) > 0 else None if self.debug and best is not None: main.system_state().draw_line(best.segment, constants.Colors.Green, "Debug") main.system_state().draw_line(robocup.Line(origin, best.segment.center()), constants.Colors.Green, "Debug") # # draw the windows if we're in debug mode # if self.debug: # for w in windows: # pts = [origin, w.segment.get_pt(0), w.segment.get_pt(1)] # color = (255, 0, 0) if w == best else (0, 255, 0) # main.system_state().draw_polygon(pts, 3, color, "Windows") return windows, best
def recalculate(self): goalie = self.subbehavior_with_name('goalie') defender1 = self.subbehavior_with_name('defender1') defender2 = self.subbehavior_with_name('defender2') behaviors = [goalie, defender1, defender2] # if we don't have any bots to work with, don't waste time calculating if all(bhvr.robot == None for bhvr in behaviors): return # A threat to our goal - something we'll actively defend against class Threat: def __init__(self, source=None): self.source = source self.ball_acquire_chance = 1.0 self.shot_chance = 1.0 self.assigned_handlers = [] self.best_shot_window = None # an OpponentRobot or Point @property def source(self): return self._source @source.setter def source(self, value): self._source = value # our source can be a Point or an OpponentRobot, this method returns the location of it @property def pos(self): if self.source != None: return self.source if isinstance(self.source, robocup.Point) else self.source.pos # a list of our behaviors that will be defending against this threat # as of now only Defender and Goalie @property def assigned_handlers(self): return self._assigned_handlers @assigned_handlers.setter def assigned_handlers(self, value): self._assigned_handlers = value # our estimate of the chance that this threat will acquire the ball # 1.0 if it already has it # otherwise, a value from 0 to 1 gauging its likelihood to receive a pass @property def ball_acquire_chance(self): return self._ball_acquire_chance @ball_acquire_chance.setter def ball_acquire_chance(self, value): self._ball_acquire_chance = value # our estimate of the chance of this threat making its shot on the goal given that it gets/has the ball # NOTE: this is calculated excluding all of our robots on the field as obstacles @property def shot_chance(self): return self._shot_chance @shot_chance.setter def shot_chance(self, value): self._shot_chance = value # his best window on our goal @property def best_shot_window(self): return self._best_shot_window @best_shot_window.setter def best_shot_window(self, value): self._best_shot_window = value # our assessment of the risk of this threat # should be between 0 and 1 @property def score(self): return self.ball_acquire_chance * self.shot_chance # available behaviors we have to assign to threats # only look at ones that have robots # as we handle threats, we remove the handlers from this list unused_threat_handlers = list(filter(lambda bhvr: bhvr.robot != None, [goalie, defender1, defender2])) def set_block_lines_for_threat_handlers(threat): if len(threat.assigned_handlers) == 0: return # make sure goalie is in the middle if len(threat.assigned_handlers) > 1: if goalie in threat.assigned_handlers: idx = threat.assigned_handlers.index(goalie) if idx != 1: del threat.assigned_handlers[idx] threat.assigned_handlers.insert(1, goalie) if threat.best_shot_window != None: center_line = robocup.Line(threat.pos, threat.best_shot_window.segment.center()) else: center_line = robocup.Line(threat.pos, constants.Field.OurGoalSegment.center()) # find the angular width that each defender can block. We then space these out accordingly angle_widths = [] for handler in threat.assigned_handlers: dist_from_threat = handler.robot.pos.dist_to(threat.pos) w = min(2.0 * math.atan2(constants.Robot.Radius, dist_from_threat), 0.15) angle_widths.append(w) # start on one edge of our available angle coverage and work counter-clockwise, # assigning block lines to the bots as we go spacing = 0.01 if len(threat.assigned_handlers) < 3 else 0.0 # spacing between each bot in radians total_angle_coverage = sum(angle_widths) + (len(angle_widths) - 1)*spacing start_vec = center_line.delta().normalized() start_vec.rotate(robocup.Point(0,0), -total_angle_coverage / 2.0) for i in range(len(angle_widths)): handler = threat.assigned_handlers[i] w = angle_widths[i] start_vec.rotate(robocup.Point(0,0), w/2.0) handler.block_line = robocup.Line(threat.pos, threat.pos + start_vec * 10) start_vec.rotate(robocup.Point(0,0), w/2.0 + spacing) def recalculate_threat_shot(threat_index): if not isinstance(threat_index, int): raise TypeError("threat_index should be an int") # ignore all of our robots excluded_robots = list(main.our_robots()) # behaviors before this threat are counted as obstacles in their TARGET position (where we've # assigned them to go, not where they are right now) hypothetical_obstacles = [] for t in threats[0:threat_index]: hypothetical_obstacles.extend(map(lambda bhvr: bhvr.move_target, t.assigned_handlers)) threat = threats[threat_index] threat.shot_chance, threat.best_shot_window = evaluation.shot.eval_shot( pos=threat.pos, target=constants.Field.OurGoalSegment, windowing_excludes=excluded_robots, hypothetical_robot_locations=[], debug=False) threats = [] # secondary threats are those that are somewhat close to our goal and open for a pass # if they're farther than this down the field, we don't consider them threats threat_max_y = constants.Field.Length / 2.0 potential_threats = [opp for opp in main.their_robots() if opp.pos.y < threat_max_y] # find the primary threat # if the ball is not moving OR it's moving towards our goal, it's the primary threat # if it's moving, but not towards our goal, the primary threat is the robot on their team most likely to catch it if main.ball().vel.mag() > 0.4: # the line the ball's moving along ball_travel_line = robocup.Line(main.ball().pos, main.ball().pos + main.ball().vel) # this is a shot on the goal! if evaluation.ball.is_moving_towards_our_goal(): ball_threat = Threat(main.ball().pos) ball_threat.ball_acquire_chance = 1.0 ball_threat.shot_chance = 1.0 threats.append(ball_threat) else: # Check for a bot that's about to capture this ball and potentially shoot on the goal # potential_receivers is an array of (OpponentRobot, angle) tuples, where the angle # is the angle between the ball_travel_line and the line from the ball to the opponent # bot - this is our metric for receiver likeliness. potential_receivers = [] for opp in potential_threats: # see if the bot is in the direction the ball is moving if (opp.pos - ball_travel_line.get_pt(0)).dot(ball_travel_line.delta()) > 0: # calculate the angle and add it to the list if it's within reason nearest_pt = ball_travel_line.nearest_point(opp.pos) dx = (nearest_pt - main.ball().pos).mag() dy = (opp.pos - nearest_pt).mag() angle = abs(math.atan2(dy, dx)) if angle < math.pi / 4.0: potential_receivers.append( (opp, 1.0) ) # choose the receiver with the smallest angle from the ball travel line if len(potential_receivers) > 0: best_receiver_tuple = min(potential_receivers, key=lambda rcrv_tuple: rcrv_tuple[1]) if best_receiver_tuple != None: receiver_threat = Threat(best_receiver_tuple[0]) receiver_threat.ball_acquire_chance = 0.9 # note: this value is arbitrary receiver_threat.shot_chance = 0.9 # FIXME: calculate this threats.append(receiver_threat) else: ball_threat = Threat(main.ball().pos) ball_threat.ball_acquire_chance = 1.0 ball_threat.shot_chance = 0.9 threats.append(ball_threat) else: # primary threat is the ball or the opponent holding it opp_with_ball = evaluation.ball.opponent_with_ball() threat = Threat(opp_with_ball if opp_with_ball != None else main.ball().pos) threat.ball_acquire_chance = 1.0 threat.shot_chance = 1.0 # FIXME: calculate, don't use 1.0 threats.append(threat) # if an opponent has the ball or is potentially about to receive the ball, # we look at potential receivers of it as threats if isinstance(threats[0].source, robocup.OpponentRobot): for opp in filter(lambda t: t.visible, potential_threats): pass_chance = evaluation.passing.eval_pass(main.ball().pos, opp.pos, excluded_robots=[opp]) # give it a small chance because the obstacles in the way could move soon and we don't want to consider it a zero threatos, ) if pass_chance < 0.001: pass_chance = 0.4 # record the threat threat = Threat(opp) threat.ball_acquire_chance = pass_chance threats.append(threat) # Now we evaluate this opponent's shot on the goal # exclude robots that have already been assigned to handle other threats threat.shot_chance, threat.best_shot_window = evaluation.shot.eval_shot( pos=opp.pos, target=constants.Field.OurGoalSegment, windowing_excludes=map(lambda bhvr: bhvr.robot, unused_threat_handlers), debug=False) if threat.shot_chance == 0: # gve it a small chance because the shot could clear up a bit later and we don't want to consider it a zero threat threat.shot_chance = 0.2 else: # the ball isn't possessed by an opponent, so we just look at opponents with shots on the goal for opp in potential_threats: # record the threat lurker = Threat(opp) lurker.ball_acquire_chance = 0.5 # note: this is a bullshit value threats.append(lurker) recalculate_threat_shot(len(threats) - 1) # only consider the top three threats threats.sort(key=lambda threat: threat.score, reverse=True) threats = threats[0:3] # print("sorted threats:") # for idx, t in enumerate(threats): # print("t[" + str(idx) + "]: " + str(t.source) + "shot: " + str(t.shot_chance) + "; pass:"******"; score:" + str(t.score)) # print("sorted threat scores: " + str(list(map(lambda t: str(t.score) + " " + str(t.source), threats)))) # print("Unused handlers: " + str(unused_threat_handlers)) # print("---------------------") smart = False if not smart: # only deal with top two threats threats_to_block = threats[0:2] # print('threats to block: ' + str(list(map(lambda t: t.source, threats_to_block)))) threat_idx = 0 while len(unused_threat_handlers) > 0: threats_to_block[threat_idx].assigned_handlers.append(unused_threat_handlers[0]) del unused_threat_handlers[0] threat_idx = (threat_idx + 1) % len(threats_to_block) for t_idx, t in enumerate(threats_to_block): recalculate_threat_shot(t_idx) set_block_lines_for_threat_handlers(t) else: # assign all of our defenders to do something while len(unused_threat_handlers) > 0: # prioritize by threat score, highest first top_threat = max(threats, key=lambda threat: threat.score) # assign the next handler to this threat handler = unused_threat_handlers[0] top_threat.assigned_handlers.append(handler) del unused_threat_handlers[0] # reassign the block line for each handler of this threat set_block_lines_for_threat_handlers(top_threat) # recalculate the shot now that we have recalculate_threat_shot(0) # tell the bots where to move / what to block and draw some debug stuff for idx, threat in enumerate(threats): # recalculate, including all current bots # FIXME: do we want this? # recalculate_threat_shot(idx) # the line they'll be shooting down/on if threat.best_shot_window != None: shot_line = robocup.Segment(threat.pos, threat.best_shot_window.segment.center()) else: shot_line = robocup.Segment(threat.pos, robocup.Point(0, 0)) # debug output if self.debug: for handler in threat.assigned_handlers: # handler.robot.add_text("Marking: " + str(threat.source), constants.Colors.White, "Defense") main.system_state().draw_circle(handler.move_target, 0.02, constants.Colors.Blue, "Defense") # draw some debug stuff if threat.best_shot_window != None: # draw shot triangle pts = [threat.pos, threat.best_shot_window.segment.get_pt(0), threat.best_shot_window.segment.get_pt(1)] shot_color = (255, 0, 0, 150) # translucent red main.system_state().draw_polygon(pts, shot_color, "Defense") main.system_state().draw_line(threat.best_shot_window.segment, constants.Colors.Red, "Defense") chance, best_window = evaluation.shot.eval_shot(threat.pos, constants.Field.OurGoalSegment) main.system_state().draw_text("Shot: " + str(int(threat.shot_chance * 100.0)) + "% / " + str(int(chance*100)) + "%", shot_line.center(), constants.Colors.White, "Defense") # draw pass lines if idx > 0: pass_line = robocup.Segment(main.ball().pos, threat.pos) main.system_state().draw_line(pass_line, constants.Colors.Red, "Defense") main.system_state().draw_text("Pass: "******"%", pass_line.center(), constants.Colors.White, "Defense")
def get_threat_list(self, unused_threat_handlers): # List of (position, score, Robot/None) threats = [] potential_threats = main.their_robots() # find the primary threat # if the ball is not moving OR it's moving towards our goal, it's the primary threat # if it's moving, but not towards our goal, the primary threat is the robot on their team most likely to catch it if (main.ball().vel.mag() > 0.4): if evaluation.ball.is_moving_towards_our_goal(): # Add tuple of pos and score threats.append((main.ball().pos, 1, None)) else: # Get all potential receivers potential_receivers = [] for opp in potential_threats: if self.estimate_potential_recievers_score(opp) == 1: potential_receivers.append((opp.pos, 1, opp)) if len(potential_receivers) > 0: # Add best receiver to threats # TODO Calc shot chance best_tuple = min(potential_receivers, key=lambda rcrv_tuple: rcrv_tuple[1]) threats.append((best_tuple[0], .81, best_tuple[2])) else: # Just deal with ball if no recievers threats.append((main.ball().pos, .9, None)) else: # Assume opp is dribbling ball if not constants.Field.OurGoalZoneShape.contains_point( main.ball().pos): # TODO: Calc shot chance threats.append((main.ball().pos, 1, None)) # if there are threats, check pass and shot chances # If the first item is not a ball, it is most likely a pass if len(threats) > 0 and threats[0][0] != main.ball().pos: for opp in potential_threats: # Exclude robots that have been assigned already excluded_bots = [] for r in map(lambda bhvr: bhvr.robot, unused_threat_handlers): excluded_bots.append(r) threats.append((opp.pos, self.estimate_risk_score( opp, excluded_bots), opp)) else: for opp in potential_threats: # Exclude all robots self.kick_eval.excluded_robots.clear() self.kick_eval.add_excluded_robot(opp) for r in main.our_robots(): self.kick_eval.add_excluded_robot(r) point, shotChance = self.kick_eval.eval_pt_to_our_goal(opp.pos) # Note: 0.5 is a bullshit value threats.append((opp.pos, 0.5 * shotChance, opp)) # Prevent threats from being below our goal line (causes incorrect pos) def _adjust_pt(threat): pt = threat[0] pt.y = max(pt.y, 0.1) return (pt,) + threat[1:] threats = list(map(_adjust_pt, threats)) return threats
def on_enter_running(self): b = skills.mark.Mark() b.mark_robot = main.their_robots()[0] self.add_subbehavior(b, name='mark', required=True)
def recalculate(self): goalie = self.subbehavior_with_name('goalie') defender1 = self.subbehavior_with_name('defender1') defender2 = self.subbehavior_with_name('defender2') behaviors = [goalie, defender1, defender2] # if we don't have any bots to work with, don't waste time calculating if all(bhvr.robot == None for bhvr in behaviors): return # A threat to our goal - something we'll actively defend against class Threat: def __init__(self, source=None): self.source = source self.ball_acquire_chance = 1.0 self.shot_chance = 1.0 self.assigned_handlers = [] self.best_shot_window = None # an OpponentRobot or Point @property def source(self): return self._source @source.setter def source(self, value): self._source = value # our source can be a Point or an OpponentRobot, this method returns the location of it @property def pos(self): if self.source != None: return self.source if isinstance( self.source, robocup.Point) else self.source.pos # a list of our behaviors that will be defending against this threat # as of now only Defender and Goalie @property def assigned_handlers(self): return self._assigned_handlers @assigned_handlers.setter def assigned_handlers(self, value): self._assigned_handlers = value # our estimate of the chance that this threat will acquire the ball # 1.0 if it already has it # otherwise, a value from 0 to 1 gauging its likelihood to receive a pass @property def ball_acquire_chance(self): return self._ball_acquire_chance @ball_acquire_chance.setter def ball_acquire_chance(self, value): self._ball_acquire_chance = value # our estimate of the chance of this threat making its shot on the goal given that it gets/has the ball # NOTE: this is calculated excluding all of our robots on the field as obstacles @property def shot_chance(self): return self._shot_chance @shot_chance.setter def shot_chance(self, value): self._shot_chance = value # his best window on our goal @property def best_shot_window(self): return self._best_shot_window @best_shot_window.setter def best_shot_window(self, value): self._best_shot_window = value # our assessment of the risk of this threat # should be between 0 and 1 @property def score(self): return self.ball_acquire_chance * self.shot_chance # available behaviors we have to assign to threats # only look at ones that have robots # as we handle threats, we remove the handlers from this list unused_threat_handlers = list( filter(lambda bhvr: bhvr.robot != None, [goalie, defender1, defender2])) def set_block_lines_for_threat_handlers(threat): if len(threat.assigned_handlers) == 0: return # make sure goalie is in the middle if len(threat.assigned_handlers) > 1: if goalie in threat.assigned_handlers: idx = threat.assigned_handlers.index(goalie) if idx != 1: del threat.assigned_handlers[idx] threat.assigned_handlers.insert(1, goalie) if threat.best_shot_window != None: center_line = robocup.Line( threat.pos, threat.best_shot_window.segment.center()) else: center_line = robocup.Line( threat.pos, constants.Field.OurGoalSegment.center()) # find the angular width that each defender can block. We then space these out accordingly angle_widths = [] for handler in threat.assigned_handlers: dist_from_threat = handler.robot.pos.dist_to(threat.pos) w = min( 2.0 * math.atan2(constants.Robot.Radius, dist_from_threat), 0.15) angle_widths.append(w) # start on one edge of our available angle coverage and work counter-clockwise, # assigning block lines to the bots as we go spacing = 0.01 if len( threat.assigned_handlers ) < 3 else 0.0 # spacing between each bot in radians total_angle_coverage = sum(angle_widths) + (len(angle_widths) - 1) * spacing start_vec = center_line.delta().normalized() start_vec.rotate(robocup.Point(0, 0), -total_angle_coverage / 2.0) for i in range(len(angle_widths)): handler = threat.assigned_handlers[i] w = angle_widths[i] start_vec.rotate(robocup.Point(0, 0), w / 2.0) handler.block_line = robocup.Line(threat.pos, threat.pos + start_vec * 10) start_vec.rotate(robocup.Point(0, 0), w / 2.0 + spacing) def recalculate_threat_shot(threat_index): if not isinstance(threat_index, int): raise TypeError("threat_index should be an int") # ignore all of our robots excluded_robots = list(main.our_robots()) # behaviors before this threat are counted as obstacles in their TARGET position (where we've # assigned them to go, not where they are right now) hypothetical_obstacles = [] for t in threats[0:threat_index]: hypothetical_obstacles.extend( map(lambda bhvr: bhvr.move_target, t.assigned_handlers)) threat = threats[threat_index] self.win_eval.excluded_robots.clear() for r in excluded_robots: self.win_eval.add_excluded_robot(r) _, threat.best_shot_window = self.win_eval.eval_pt_to_our_goal( threat.pos) if threat.best_shot_window is not None: threat.shot_chance = threat.best_shot_window.shot_success else: threat.shot_chance = 0.0 threats = [] # secondary threats are those that are somewhat close to our goal and open for a pass # if they're farther than this down the field, we don't consider them threats threat_max_y = constants.Field.Length / 2.0 potential_threats = [ opp for opp in main.their_robots() if opp.pos.y < threat_max_y ] # find the primary threat # if the ball is not moving OR it's moving towards our goal, it's the primary threat # if it's moving, but not towards our goal, the primary threat is the robot on their team most likely to catch it if main.ball().vel.mag() > 0.4: # the line the ball's moving along ball_travel_line = robocup.Line(main.ball().pos, main.ball().pos + main.ball().vel) # this is a shot on the goal! if evaluation.ball.is_moving_towards_our_goal(): ball_threat = Threat(main.ball().pos) ball_threat.ball_acquire_chance = 1.0 ball_threat.shot_chance = 1.0 threats.append(ball_threat) else: # Check for a bot that's about to capture this ball and potentially shoot on the goal # potential_receivers is an array of (OpponentRobot, angle) tuples, where the angle # is the angle between the ball_travel_line and the line from the ball to the opponent # bot - this is our metric for receiver likeliness. potential_receivers = [] for opp in potential_threats: # see if the bot is in the direction the ball is moving if (opp.pos - ball_travel_line.get_pt(0)).dot( ball_travel_line.delta()) > 0: # calculate the angle and add it to the list if it's within reason nearest_pt = ball_travel_line.nearest_point(opp.pos) dx = (nearest_pt - main.ball().pos).mag() dy = (opp.pos - nearest_pt).mag() angle = abs(math.atan2(dy, dx)) if angle < math.pi / 4.0: potential_receivers.append((opp, 1.0)) # choose the receiver with the smallest angle from the ball travel line if len(potential_receivers) > 0: best_receiver_tuple = min( potential_receivers, key=lambda rcrv_tuple: rcrv_tuple[1]) if best_receiver_tuple != None: receiver_threat = Threat(best_receiver_tuple[0]) receiver_threat.ball_acquire_chance = 0.9 # note: this value is arbitrary receiver_threat.shot_chance = 0.9 # FIXME: calculate this threats.append(receiver_threat) else: ball_threat = Threat(main.ball().pos) ball_threat.ball_acquire_chance = 1.0 ball_threat.shot_chance = 0.9 threats.append(ball_threat) else: # primary threat is the ball or the opponent holding it opp_with_ball = evaluation.ball.opponent_with_ball() threat = Threat( opp_with_ball if opp_with_ball != None else main.ball().pos) threat.ball_acquire_chance = 1.0 threat.shot_chance = 1.0 # FIXME: calculate, don't use 1.0 threats.append(threat) # if an opponent has the ball or is potentially about to receive the ball, # we look at potential receivers of it as threats if isinstance(threats[0].source, robocup.OpponentRobot): for opp in filter(lambda t: t.visible, potential_threats): pass_chance = evaluation.passing.eval_pass( main.ball().pos, opp.pos, excluded_robots=[opp]) # give it a small chance because the obstacles in the way could move soon and we don't want to consider it a zero threatos, ) if pass_chance < 0.001: pass_chance = 0.4 # record the threat threat = Threat(opp) threat.ball_acquire_chance = pass_chance threats.append(threat) # Now we evaluate this opponent's shot on the goal # exclude robots that have already been assigned to handle other threats self.win_eval.excluded_robots.clear() for r in map(lambda bhvr: bhvr.robot, unused_threat_handlers): self.win_eval.add_excluded_robot(r) _, threat.best_shot_window = self.win_eval.eval_pt_to_our_goal( opp.pos) if threat.best_shot_window is not None: threat.shot_chance = threat.best_shot_window.shot_success else: threat.shot_chance = 0.0 if threat.shot_chance == 0: # gve it a small chance because the shot could clear up a bit later and we don't want to consider it a zero threat threat.shot_chance = 0.2 else: # the ball isn't possessed by an opponent, so we just look at opponents with shots on the goal for opp in potential_threats: # record the threat lurker = Threat(opp) lurker.ball_acquire_chance = 0.5 # note: this is a bullshit value threats.append(lurker) recalculate_threat_shot(len(threats) - 1) # only consider the top three threats threats.sort(key=lambda threat: threat.score, reverse=True) threats = threats[0:3] # print("sorted threats:") # for idx, t in enumerate(threats): # print("t[" + str(idx) + "]: " + str(t.source) + "shot: " + str(t.shot_chance) + "; pass:"******"; score:" + str(t.score)) # print("sorted threat scores: " + str(list(map(lambda t: str(t.score) + " " + str(t.source), threats)))) # print("Unused handlers: " + str(unused_threat_handlers)) # print("---------------------") smart = False if not smart: # only deal with top two threats threats_to_block = threats[0:2] # print('threats to block: ' + str(list(map(lambda t: t.source, threats_to_block)))) threat_idx = 0 while len(unused_threat_handlers) > 0: threats_to_block[threat_idx].assigned_handlers.append( unused_threat_handlers[0]) del unused_threat_handlers[0] threat_idx = (threat_idx + 1) % len(threats_to_block) for t_idx, t in enumerate(threats_to_block): recalculate_threat_shot(t_idx) set_block_lines_for_threat_handlers(t) else: # assign all of our defenders to do something while len(unused_threat_handlers) > 0: # prioritize by threat score, highest first top_threat = max(threats, key=lambda threat: threat.score) # assign the next handler to this threat handler = unused_threat_handlers[0] top_threat.assigned_handlers.append(handler) del unused_threat_handlers[0] # reassign the block line for each handler of this threat set_block_lines_for_threat_handlers(top_threat) # recalculate the shot now that we have recalculate_threat_shot(0) # tell the bots where to move / what to block and draw some debug stuff for idx, threat in enumerate(threats): # recalculate, including all current bots # FIXME: do we want this? # recalculate_threat_shot(idx) # the line they'll be shooting down/on if threat.best_shot_window != None: shot_line = robocup.Segment( threat.pos, threat.best_shot_window.segment.center()) else: shot_line = robocup.Segment(threat.pos, robocup.Point(0, 0)) # debug output if self.debug: for handler in threat.assigned_handlers: # handler.robot.add_text("Marking: " + str(threat.source), constants.Colors.White, "Defense") main.system_state().draw_circle(handler.move_target, 0.02, constants.Colors.Blue, "Defense") # draw some debug stuff if threat.best_shot_window != None: # draw shot triangle pts = [ threat.pos, threat.best_shot_window.segment.get_pt(0), threat.best_shot_window.segment.get_pt(1) ] shot_color = (255, 0, 0, 150) # translucent red main.system_state().draw_polygon(pts, shot_color, "Defense") main.system_state().draw_segment( threat.best_shot_window.segment, constants.Colors.Red, "Defense") self.win_eval.excluded_robots.clear() _, best_window = self.win_eval.eval_pt_to_our_goal( threat.pos) if best_window is not None: chance = best_window.shot_success else: chance = 0.0 main.system_state().draw_text( "Shot: " + str(int(threat.shot_chance * 100.0)) + "% / " + str(int(chance * 100)) + "%", shot_line.center(), constants.Colors.White, "Defense") # draw pass lines if idx > 0: pass_line = robocup.Segment(main.ball().pos, threat.pos) main.system_state().draw_line(pass_line, constants.Colors.Red, "Defense") main.system_state().draw_text( "Pass: "******"%", pass_line.center(), constants.Colors.White, "Defense")
def execute_running(self): their_robots = main.their_robots() mark_one = self.subbehavior_with_name('mark_one') mark_two = self.subbehavior_with_name('mark_two') centerCircle = robocup.Circle(constants.Field.CenterPoint, constants.Field.CenterRadius) # Don't select robots that are # 1. Not on our side of the field # 2. behind or inside the goal circle mark_robot_right = list(filter( lambda robot: (robot.pos.x >= 0 and robot.pos.y < constants.Field.Length * TheirKickoff.FieldRatio and constants.Field.FieldRect.contains_point(robot.pos) and not centerCircle.contains_point(robot.pos)), their_robots)) # Don't select robots that are # 1. Not on our side of the field # 2. behind or inside the goal circle # 3. Not the robot selected before mark_robot_left = list(filter( lambda robot: (robot.pos.x <= 0 and robot.pos.y < constants.Field.Length * TheirKickoff.FieldRatio and constants.Field.FieldRect.contains_point(robot.pos) and not centerCircle.contains_point(robot.pos) and robot != mark_one.mark_robot), their_robots)) # Special cases if len(mark_robot_left) + len(mark_robot_right) == 0: # Can't do anything mark_robot_left = None mark_robot_right = None elif len(mark_robot_left) + len(mark_robot_right) == 1: if len(mark_robot_left) == 1: mark_robot_right = mark_robot_left[0] mark_robot_left = None else: mark_robot_right = mark_robot_right[0] mark_robot_left = None elif len(mark_robot_left) == 0: mark_robot_right = mark_robot_right mark_robot_left = mark_robot_right elif len(mark_robot_right) == 0: mark_robot_right = mark_robot_left mark_robot_left = mark_robot_left # Else, everything can proceed as normal (pick best one from each side) # Make every element a list to normalize for the next step if type(mark_robot_right) is not list and mark_robot_right is not None: mark_robot_right = [mark_robot_right] if type(mark_robot_left) is not list and mark_robot_left is not None: mark_robot_left = [mark_robot_left] # Select best robot from candidate lists selected = None if mark_robot_right is not None: mark_robot_right = min(mark_robot_right, key=lambda robot: robot.pos.y).pos selected = robocup.Point(mark_robot_right) else: mark_robot_right = robocup.Point(TheirKickoff.DefaultDist, constants.Field.Length / 2) # Set x and y seperately as we want a constant y value (just behind the kick off line) mark_robot_right.y = min( constants.Field.Length / 2 - TheirKickoff.LineBuffer, mark_robot_right.y) mark_robot_right.x = self.absmin(mark_robot_right.x, TheirKickoff.DefaultDist) mark_one.mark_point = mark_robot_right # Do the same thing as above on the left robot. if mark_robot_left is not None: # Don't mark the same robot twice mark_robot_left = filter( lambda x: True if selected is None else not x.pos.nearly_equals(selected), mark_robot_left) mark_robot_left = min(mark_robot_left, key=lambda robot: robot.pos.y).pos else: mark_robot_left = robocup.Point(-TheirKickoff.DefaultDist, constants.Field.Length / 2) mark_robot_left.y = min( constants.Field.Length / 2 - TheirKickoff.LineBuffer, mark_robot_left.y) mark_robot_left.x = self.absmin(mark_robot_left.x, TheirKickoff.DefaultDist) mark_two.mark_point = mark_robot_left
def get_threat_list(self, unused_threat_handlers): # List of (position, score, Robot/None) threats = [] potential_threats = main.their_robots() # find the primary threat # if the ball is not moving OR it's moving towards our goal, it's the primary threat # if it's moving, but not towards our goal, the primary threat is the robot on their team most likely to catch it if (main.ball().vel.mag() > 0.4): if evaluation.ball.is_moving_towards_our_goal(): # Add tuple of pos and score threats.append((main.ball().pos, 1, None)) else: # Get all potential receivers potential_receivers = [] for opp in potential_threats: if self.estimate_potential_recievers_score(opp) == 1: potential_receivers.append((opp.pos, 1, opp)) if len(potential_receivers) > 0: # Add best receiver to threats # TODO Calc shot chance best_tuple = min(potential_receivers, key=lambda rcrv_tuple: rcrv_tuple[1]) threats.append((best_tuple[0], .81, best_tuple[2])) else: # Just deal with ball if no recievers threats.append((main.ball().pos, .9, None)) else: # Assume opp is dribbling ball if not constants.Field.OurGoalZoneShape.contains_point( main.ball().pos): # TODO: Calc shot chance threats.append((main.ball().pos, 1, None)) # if there are threats, check pass and shot chances # If the first item is not a ball, it is most likely a pass if len(threats) > 0 and threats[0][0] != main.ball().pos: for opp in potential_threats: # Exclude robots that have been assigned already excluded_bots = [] for r in map(lambda bhvr: bhvr.robot, unused_threat_handlers): excluded_bots.append(r) threats.append( (opp.pos, self.estimate_risk_score(opp, excluded_bots), opp)) else: for opp in potential_threats: # Exclude all robots self.kick_eval.excluded_robots.clear() self.kick_eval.add_excluded_robot(opp) for r in main.our_robots(): self.kick_eval.add_excluded_robot(r) point, shotChance = self.kick_eval.eval_pt_to_our_goal(opp.pos) # Note: 0.5 is a bullshit value threats.append((opp.pos, 0.5 * shotChance, opp)) # Prevent threats from being below our goal line (causes incorrect pos) def _adjust_pt(threat): pt = threat[0] pt.y = max(pt.y, 0.1) return (pt, ) + threat[1:] threats = list(map(_adjust_pt, threats)) return threats
def find_gap(target_pos=constants.Field.TheirGoalSegment.center(), max_shooting_angle=60, robot_offset=8, dist_from_point=.75): if (not main.ball().valid): return target_pos # Find the hole in the defenders to kick at # The limit is 20 cm so any point past it should be defenders right there win_eval = robocup.WindowEvaluator(main.system_state()) # 500 cm min circle distance plus the robot width test_distance = dist_from_point + constants.Robot.Radius # +- max offset to dodge ball max_angle = max_shooting_angle * constants.DegreesToRadians # How much left and right of a robot to give # Dont make this too big or it will always go far to the right or left of the robots robot_angle_offset = robot_offset * constants.DegreesToRadians zero_point = robocup.Point(0, 0) # Limit the angle so as we get closer, we dont miss the goal completely as much goal_vector = target_pos - main.ball().pos max_length_vector = robocup.Point(constants.Field.Length, constants.Field.Width) goal_limit = (goal_vector.mag() / max_length_vector.mag()) * max_angle # Limit on one side so we dont directly kick out of bounds # Add in the angle from the sideline to the target field_limit = (1 - abs(main.ball().pos.x) / (constants.Field.Width / 2)) * max_angle field_limit = field_limit + goal_vector.angle_between(robocup.Point(0, 1)) # Limit the angle based on the opponent robots to try and always minimize the left_robot_limit = 0 right_robot_limit = 0 for robot in main.their_robots(): ball_to_bot = robot.pos - main.ball().pos # Add an extra radius as wiggle room # kick eval already deals with the wiggle room so it isn't needed there if (ball_to_bot.mag() <= test_distance + constants.Robot.Radius): angle = goal_vector.angle_between(ball_to_bot) # Try and rotate onto the goal vector # if we actually do, then the robot is to the right of the ball vector ball_to_bot.rotate(zero_point, angle) if (ball_to_bot.angle_between(goal_vector) < 0.01): right_robot_limit = max(right_robot_limit, angle + robot_angle_offset) else: left_robot_limit = max(left_robot_limit, angle + robot_angle_offset) else: win_eval.add_excluded_robot(robot) # Angle limit on each side of the bot->goal vector left_angle = max_angle right_angle = max_angle # Make sure we limit the correct side due to the field if main.ball().pos.x < 0: left_angle = min(left_angle, field_limit) else: right_angle = min(right_angle, field_limit) # Limit due to goal left_angle = min(left_angle, goal_limit) right_angle = min(right_angle, goal_limit) # Limit to just over the robots if (left_robot_limit is not 0): left_angle = min(left_angle, left_robot_limit) if (right_robot_limit is not 0): right_angle = min(right_angle, right_robot_limit) # Get the angle that we need to rotate the target angle behind the defenders # since kick eval doesn't support a nonsymmetric angle around a target rotate_target_angle = (left_angle + -right_angle)/2 target_width = (left_angle + right_angle) target_point = goal_vector.normalized() * test_distance target_point.rotate(zero_point, rotate_target_angle) windows, window = win_eval.eval_pt_to_pt(main.ball().pos, target_point + main.ball().pos, target_width) # Test draw points target_point.rotate(zero_point, target_width/2) p1 = target_point + main.ball().pos target_point.rotate(zero_point, -target_width) p2 = target_point + main.ball().pos p3 = main.ball().pos main.system_state().draw_polygon([p1, p2, p3], (0, 0, 255), "Free Kick search zone") is_opponent_blocking = False for robot in main.their_robots(): if (goal_vector.dist_to(robot.pos) < constants.Robot.Radius and (main.ball().pos - robot.pos).mag() < test_distance): is_opponent_blocking = True # Vector from ball position to the goal ideal_shot = (target_pos - main.ball().pos).normalized() # If on our side of the field and there are enemy robots around us, # prioritize passing forward vs passing towards their goal # Would have to change this if we are not aiming for their goal if main.ball().pos.y < constants.Field.Length / 2 and len(windows) > 1: ideal_shot = robocup.Point(0, 1) main.system_state().draw_line(robocup.Line(main.ball().pos, target_pos), (0, 255, 0), "Target Point") # Weights for determining best shot k1 = 1.5 # Weight of closeness to ideal shot k2 = 1 # Weight of shot chance # Iterate through all possible windows to find the best possible shot if windows: best_shot = window.segment.center() best_weight = 0 for wind in windows: pos_to_wind = (wind.segment.center() - main.ball().pos).normalized() dot_prod = pos_to_wind.dot(ideal_shot) weight = k1 * dot_prod + k2 * wind.shot_success if weight > best_weight: best_weight = weight best_shot = wind.segment.center() main.system_state().draw_line(robocup.Line(main.ball().pos, best_shot), (255, 255, 0), "Target Shot") best_shot = robocup.Point(0,1) + main.ball().pos return best_shot else: return constants.Field.TheirGoalSegment.center()
def execute_running(self): super().execute_running() striker = self.subbehavior_with_name('striker') support1 = self.subbehavior_with_name('support1') support2 = self.subbehavior_with_name('support2') supports = [support1, support2] # project ball location a bit into the future ball_proj = evaluation.ball.predict(main.ball().pos, main.ball().vel, t=0.75) # find closest opponent to striker closest_dist_to_striker, closest_opp_to_striker = float("inf"), None if striker.robot != None: for opp in main.their_robots(): d = opp.pos.dist_to(striker.robot.pos) if d < closest_dist_to_striker: closest_dist_to_striker, closest_opp_to_striker = d, opp striker_engaged = striker.robot != None and closest_dist_to_striker < Basic122.SupportBackoffThresh # pick out which opponents our defenders should 'mark' # TODO: explain nrOppClose = 0 bestOpp1, bestOpp2 = None, None bestDistSq1, bestDistSq2 = float("inf"), float("inf") for opp in main.their_robots(): # use dist from goal rather than just y-coord to handle corners better oppDistSq = opp.pos.magsq() if not (striker_engaged and opp == closest_opp_to_striker): if oppDistSq < bestDistSq1: bestDistSq2, bestOpp2 = bestDistSq1, bestOpp1 bestDistSq1, bestOpp1 = oppDistSq, opp elif oppDistSq < bestDistSq2: bestDistSq2, bestOpp2 = oppDistSq, opp if oppDistSq < constants.Field.Length**2 / 4.0: nrOppClose += 1 # handle the case of having no good robots to mark if bestOpp1 == None and support1.robot != None: support1.mark_robot = None support1.robot.add_text("No mark target", (255, 255, 255), "RobotText") if striker.robot != None: support1.robot.add_text("Static Support", (255, 255, 255), "RobotText") support_goal = striker.robot.pos support_goal.x *= -1.0 if abs(support_goal.x) < 0.2: support_goal.x = -1.0 if support_goal.x < 0 else 1.0 if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0: support_goal.y = max(support_goal.y * Basic122.OffenseSupportRatio, 0.3) else: support_goal.y = max(support_goal.y * Basic122.DefenseSupportRatio, 0.3) support1.robot.move_to(support_goal) support1.robot.face(ball_proj) # sit around and do jack shit... # TODO: make it do something useful if bestOpp2 == None and support2.robot != None: support2.mark_robot = None support2.robot.add_text("No mark target", (255, 255, 255), "RobotText") if striker.robot != None: support2.robot.add_text("Static Support", (255, 255, 255), "RobotText") support_goal = striker.robot.pos support_goal.x *= -1.0 if abs(support_goal.x) < 0.2: support_goal.x = -1.0 if support_goal.x < 0 else 1.0 if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0: support_goal.y = max(support_goal.y * Basic122.OffenseSupportRatio, 0.3) else: support_goal.y = max(support_goal.y * Basic122.DefenseSupportRatio, 0.3) support2.robot.move_to(support_goal) support2.robot.face(ball_proj) # reassign support robots' mark targets based on dist sq and hysteresis coeff new_dists = [bestDistSq1, bestDistSq2] new_bots = [bestOpp1, bestOpp2] for i in range(2): support = supports[i] if new_bots[i] != None: cur_dist_sq = ( support.mark_robot.pos - ball_proj).magsq() if support.mark_robot else float("inf") if new_dists[i] < cur_dist_sq * Basic122.MarkHysteresisCoeff: support.mark_robot = new_bots[i] # if the supports are farther from the ball, they can mark further away if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0: for support in supports: support.ratio = Basic122.OffenseSupportRatio else: for support in supports: support.ratio = Basic122.DefenseSupportRatio # raise NotImplementedError("Make support robots avoid the shot channel") # FROM C++: # Polygon shot_obs; # shot_obs.vertices.push_back(Geometry2d::Point(Field_GoalWidth / 2, Field_Length)); # shot_obs.vertices.push_back(Geometry2d::Point(-Field_GoalWidth / 2, Field_Length)); # shot_obs.vertices.push_back(ballProj); # TODO: this would be a good place for a "keep-trying container behavior" # make the kicker try again if it already kicked if not striker.is_in_state(behavior.Behavior.State.running): striker.restart()
def on_enter_running(self): b = skills.goalside_mark.Goalside_Mark() b.mark_robot = main.their_robots()[0] self.add_subbehavior(b, name='goalside mark', required=True)
def find_gap(target_pos=constants.Field.TheirGoalSegment.center(), max_shooting_angle=60, robot_offset=8, dist_from_point=.75): if (not main.ball().valid): return target_pos # Find the hole in the defenders to kick at # The limit is 20 cm so any point past it should be defenders right there win_eval = robocup.WindowEvaluator(main.system_state()) # 500 cm min circle distance plus the robot width test_distance = dist_from_point + constants.Robot.Radius # +- max offset to dodge ball max_angle = max_shooting_angle * constants.DegreesToRadians # How much left and right of a robot to give # Dont make this too big or it will always go far to the right or left of the robots robot_angle_offset = robot_offset * constants.DegreesToRadians zero_point = robocup.Point(0, 0) # Limit the angle so as we get closer, we dont miss the goal completely as much goal_vector = target_pos - main.ball().pos max_length_vector = robocup.Point(constants.Field.Length, constants.Field.Width) goal_limit = (goal_vector.mag() / max_length_vector.mag()) * max_angle # Limit on one side so we dont directly kick out of bounds # Add in the angle from the sideline to the target field_limit = (1 - abs(main.ball().pos.x) / (constants.Field.Width / 2)) * max_angle field_limit = field_limit + goal_vector.angle_between(robocup.Point(0, 1)) # Limit the angle based on the opponent robots to try and always minimize the left_robot_limit = 0 right_robot_limit = 0 for robot in main.their_robots(): ball_to_bot = robot.pos - main.ball().pos # Add an extra radius as wiggle room # kick eval already deals with the wiggle room so it isn't needed there if (ball_to_bot.mag() <= test_distance + constants.Robot.Radius): angle = goal_vector.angle_between(ball_to_bot) # Try and rotate onto the goal vector # if we actually do, then the robot is to the right of the ball vector ball_to_bot.rotate(zero_point, angle) if (ball_to_bot.angle_between(goal_vector) < 0.01): right_robot_limit = max(right_robot_limit, angle + robot_angle_offset) else: left_robot_limit = max(left_robot_limit, angle + robot_angle_offset) else: win_eval.add_excluded_robot(robot) # Angle limit on each side of the bot->goal vector left_angle = max_angle right_angle = max_angle # Make sure we limit the correct side due to the field if main.ball().pos.x < 0: left_angle = min(left_angle, field_limit) else: right_angle = min(right_angle, field_limit) # Limit due to goal left_angle = min(left_angle, goal_limit) right_angle = min(right_angle, goal_limit) # Limit to just over the robots if (left_robot_limit is not 0): left_angle = min(left_angle, left_robot_limit) if (right_robot_limit is not 0): right_angle = min(right_angle, right_robot_limit) # Get the angle that we need to rotate the target angle behind the defenders # since kick eval doesn't support a nonsymmetric angle around a target rotate_target_angle = (left_angle + -right_angle)/2 target_width = (left_angle + right_angle) target_point = goal_vector.normalized() * test_distance target_point.rotate(zero_point, rotate_target_angle) windows, window = win_eval.eval_pt_to_pt(main.ball().pos, target_point + main.ball().pos, target_width) # Test draw points target_point.rotate(zero_point, target_width/2) p1 = target_point + main.ball().pos target_point.rotate(zero_point, -target_width) p2 = target_point + main.ball().pos p3 = main.ball().pos main.system_state().draw_polygon([p1, p2, p3], (0, 0, 255), "Free Kick search zone") is_opponent_blocking = False for robot in main.their_robots(): if (goal_vector.dist_to(robot.pos) < constants.Robot.Radius and (main.ball().pos - robot.pos).mag() < test_distance): is_opponent_blocking = True # Vector from ball position to the goal ideal_shot = (target_pos - main.ball().pos).normalized() # If on our side of the field and there are enemy robots around us, # prioritize passing forward vs passing towards their goal # Would have to change this if we are not aiming for their goal if main.ball().pos.y < constants.Field.Length / 2 and len(windows) > 1: ideal_shot = robocup.Point(0, 1) main.system_state().draw_line(robocup.Line(main.ball().pos, target_pos), (0, 255, 0), "Target Point") # Weights for determining best shot k1 = 1.5 # Weight of closeness to ideal shot k2 = 1 # Weight of shot chance # print("ideal shot:", ideal_shot) # print("number of windows:", len(windows)) # Iterate through all possible windows to find the best possible shot if windows: best_shot = window.segment.center() best_weight = 0 for wind in windows: pos_to_wind = (wind.segment.center() - main.ball().pos).normalized() dot_prod = pos_to_wind.dot(ideal_shot) # print("weighted dot product:", dot_prod) # print("weighted shot chance:", wind.shot_success) weight = k1 * dot_prod + k2 * wind.shot_success if weight > best_weight: best_weight = weight best_shot = wind.segment.center() main.system_state().draw_line(robocup.Line(main.ball().pos, best_shot), (255, 255, 0), "Target Shot") best_shot = robocup.Point(0,1) + main.ball().pos return best_shot else: return constants.Field.TheirGoalSegment.center()
def execute_running(self): striker = self.subbehavior_with_name('striker') support1 = self.subbehavior_with_name('support1') support2 = self.subbehavior_with_name('support2') supports = [support1, support2] # project ball location a bit into the future ball_proj = evaluation.ball.predict(main.ball().pos, main.ball().vel, t=0.75) # find closest opponent to striker closest_dist_to_striker, closest_opp_to_striker = float("inf"), None if striker.robot != None: for opp in main.their_robots(): d = opp.pos.dist_to(striker.robot.pos) if d < closest_dist_to_striker: closest_dist_to_striker, closest_opp_to_striker = d, opp striker_engaged = striker.robot != None and closest_dist_to_striker < Basic122.SupportBackoffThresh # pick out which opponents our defenders should 'mark' # TODO: explain nrOppClose = 0 bestOpp1, bestOpp2 = None, None bestDistSq1, bestDistSq2 = float("inf"), float("inf") for opp in main.their_robots(): # use dist from goal rather than just y-coord to handle corners better oppDistSq = opp.pos.magsq() if not (striker_engaged and opp == closest_opp_to_striker): if oppDistSq < bestDistSq1: bestDistSq2, bestOpp2 = bestDistSq1, bestOpp1 bestDistSq1, bestOpp1 = oppDistSq, opp elif oppDistSq < bestDistSq2: bestDistSq2, bestOpp2 = oppDistSq, opp if oppDistSq < constants.Field.Length**2 / 4.0: nrOppClose += 1 # handle the case of having no good robots to mark if bestOpp1 == None and support1.robot != None: support1.mark_robot = None support1.robot.add_text("No mark target", (255,255,255), "RobotText") if striker.robot != None: support1.robot.add_text("Static Support", (255,255,255), "RobotText") support_goal = striker.robot.pos support_goal.x *= -1.0 if abs(support_goal.x) < 0.2: support_goal.x = -1.0 if support_goal.x < 0 else 1.0 if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0: support_goal.y = max(support_goal.y * Basic122.OffenseSupportRatio, 0.3) else: support_goal.y = max(support_goal.y * Basic122.DefenseSupportRatio, 0.3) support1.robot.move_to(support_goal) support1.robot.face(ball_proj) # sit around and do jack shit... # TODO: make it do something useful if bestOpp2 == None and support2.robot != None: support2.mark_robot = None support2.robot.add_text("No mark target", (255,255,255), "RobotText") if striker.robot != None: support2.robot.add_text("Static Support", (255,255,255), "RobotText") support_goal = striker.robot.pos support_goal.x *= -1.0 if abs(support_goal.x) < 0.2: support_goal.x = -1.0 if support_goal.x < 0 else 1.0 if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0: support_goal.y = max(support_goal.y * Basic122.OffenseSupportRatio, 0.3) else: support_goal.y = max(support_goal.y * Basic122.DefenseSupportRatio, 0.3) support2.robot.move_to(support_goal) support2.robot.face(ball_proj) # reassign support robots' mark targets based on dist sq and hysteresis coeff new_dists = [bestDistSq1, bestDistSq2] new_bots = [bestOpp1, bestOpp2] for i in range(2): support = supports[i] if new_bots[i] != None: cur_dist_sq = (support.mark_robot.pos - ball_proj).magsq() if support.mark_robot else float("inf") if new_dists[i] < cur_dist_sq * Basic122.MarkHysteresisCoeff: support.mark_robot = new_bots[i] # if the supports are farther from the ball, they can mark further away if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0: for support in supports: support.ratio = Basic122.OffenseSupportRatio else: for support in supports: support.ratio = Basic122.DefenseSupportRatio # keep support robots away from the striker if striker.robot != None: for supp in [support1, support2]: if supp.robot != None: supp.robot.set_avoid_teammate_radius(striker.robot.shell_id(), Basic122.SupportAvoidTeammateRadius) # raise NotImplementedError("Make support robots avoid the shot channel") # FROM C++: # Polygon shot_obs; # shot_obs.vertices.push_back(Geometry2d::Point(Field_GoalWidth / 2, Field_Length)); # shot_obs.vertices.push_back(Geometry2d::Point(-Field_GoalWidth / 2, Field_Length)); # shot_obs.vertices.push_back(ballProj); # TODO: this would be a good place for a "keep-trying container behavior" # make the kicker try again if it already kicked if not striker.is_in_state(behavior.Behavior.State.running): striker.restart()
def has_ball(self): closeIndicator = False for r in main.their_robots(): closeIndicator = closeIndicator or ( r.pos - main.ball().pos).mag() < self.ball_lost_distance return closeIndicator