def utility_score(self, bot) -> float: if self.temp_utility_desire_boost > 0: self.temp_utility_desire_boost = max(0, self.temp_utility_desire_boost - bot.info.dt) elif self.temp_utility_desire_boost < 0: self.temp_utility_desire_boost = min(0, self.temp_utility_desire_boost + bot.info.dt) car = bot.info.my_car ball_soon = predict.ball_predict(bot, 1) arena_length2 = bot.info.team_sign * Field.LENGTH2 own_half_01 = clip01(remap(arena_length2, -arena_length2, 0.0, 1.1, ball_soon.pos.y)) close_to_ball01 = clip01(1.0 - norm(car.pos - ball_soon.pos) / 3500) ** 0.5 reachable_ball = predict.ball_predict(bot, predict.time_till_reach_ball(bot.info.my_car, bot.info.ball)) self.ball_to_goal_right = bot.info.opp_goal.right_post - reachable_ball.pos self.ball_to_goal_left = bot.info.opp_goal.left_post - reachable_ball.pos self.aim_cone = AimCone(self.ball_to_goal_right, self.ball_to_goal_left) car_to_ball = reachable_ball.pos - bot.info.my_car.pos in_position = self.aim_cone.contains_direction(car_to_ball) # Chase ball right after kickoff. High right after kickoff kickoff_bias01 = max(0, 1 - bot.info.time_since_last_kickoff * 0.3) * float(bot.info.my_car.objective == Objective.UNKNOWN) obj_bonus = { Objective.UNKNOWN: 0, Objective.GO_FOR_IT: 0.2, Objective.FOLLOW_UP: 0, Objective.ROTATE_BACK_OR_DEF: -0.2, }[bot.info.my_car.objective] return clip01(close_to_ball01 * own_half_01 + 0.1 * in_position + self.temp_utility_desire_boost + kickoff_bias01) + obj_bonus
def any_touch(self, bot, time: float, dodge_hit: bool = True): ball_soon = ball_predict(bot, time) car_to_ball = ball_soon.pos - bot.info.my_car.pos return self.towards(bot, ball_soon.pos + car_to_ball, time, dodge_hit) or SimpleControllerState()
def utility(self, bot) -> float: ball_soon = predict.ball_predict(bot, 1) arena_length2 = bot.info.team_sign * Field.LENGTH / 2 own_half_01 = clip01( remap(arena_length2, -arena_length2, 0.0, 1.1, ball_soon.pos.y)) reachable_ball = predict.ball_predict( bot, predict.time_till_reach_ball(bot.info.my_car, bot.info.ball)) self.ball_to_goal_right = bot.info.enemy_goal_right - reachable_ball.pos self.ball_to_goal_left = bot.info.enemy_goal_left - reachable_ball.pos self.aim_cone = AimCone(self.ball_to_goal_right, self.ball_to_goal_left) car_to_ball = reachable_ball.pos - bot.info.my_car.pos in_position = self.aim_cone.contains_direction(car_to_ball) return clip01(own_half_01 + 0.1 * in_position)
def utility(self, bot) -> float: team_sign = bot.info.team_sign length = team_sign * Field.LENGTH / 2 ball_own_half_01 = clip01( remap(-length, length, -0.2, 1.2, bot.info.ball.pos.y)) reachable_ball = predict.ball_predict( bot, predict.time_till_reach_ball(bot.info.my_car, bot.info.ball)) car_to_ball = reachable_ball.pos - bot.info.my_car.pos in_position = self.aim_cone.contains_direction(car_to_ball, math.pi / 8) return ball_own_half_01 * in_position
def towards(self, bot, target: Vec3, time: float, allowed_uncertainty: float = 0.3, dodge_hit: bool = True): ball_soon = ball_predict(bot, time) ball_soon_to_target_dir = normalize(target - ball_soon.pos) right = dot(axis_to_rotation(Vec3(z=allowed_uncertainty)), ball_soon_to_target_dir) left = dot(axis_to_rotation(Vec3(z=-allowed_uncertainty)), ball_soon_to_target_dir) aim_cone = AimCone(right, left) aim_cone.draw(bot, ball_soon.pos, r=0, g=0) return self.with_aiming(bot, aim_cone, time, dodge_hit)
def utility_score(self, bot) -> float: team_sign = bot.info.team_sign length = team_sign * Field.LENGTH / 2 ball_own_half_01 = clip01( remap(-length, length, -0.2, 1.2, bot.info.ball.pos.y)) reachable_ball = predict.ball_predict( bot, predict.time_till_reach_ball(bot.info.my_car, bot.info.ball)) car_to_ball = reachable_ball.pos - bot.info.my_car.pos in_position = self.aim_cone.contains_direction(car_to_ball, math.pi / 8) obj_bonus = { Objective.UNKNOWN: 0, Objective.GO_FOR_IT: 0.15, Objective.FOLLOW_UP: 0, Objective.ROTATE_BACK_OR_DEF: 0.0, }[bot.info.my_car.objective] return ball_own_half_01 * in_position + obj_bonus
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: # Read packet if not self.info.field_info_loaded: self.info.read_field_info(self.get_field_info()) if not self.info.field_info_loaded: return SimpleControllerState() self.info.read_packet(packet) self.analyzer.update(self) # Check if match is over if packet.game_info.is_match_ended: return celebrate(self) # Assume we won! self.renderer.begin_rendering() controller = self.use_brain() # Additional rendering if self.do_rendering: doing = self.maneuver or self.choice state_color = { Objective.GO_FOR_IT: self.renderer.lime(), Objective.FOLLOW_UP: self.renderer.yellow(), Objective.ROTATE_BACK_OR_DEF: self.renderer.red(), Objective.UNKNOWN: self.renderer.team_color(alt_color=True) }[self.info.my_car.objective] if doing is not None: self.renderer.draw_string_2d(330, 700 + self.index * 20, 1, 1, f"{self.name}:", self.renderer.team_color(alt_color=True)) self.renderer.draw_string_2d(500, 700 + self.index * 20, 1, 1, doing.__class__.__name__, state_color) self.renderer.draw_rect_3d(self.info.my_car.pos + Vec3(z=60), 16, 16, True, state_color) reach_pos = predict.ball_predict(self, self.info.my_car.reach_ball_time).pos self.renderer.draw_line_3d(self.info.my_car.pos, reach_pos, self.renderer.white()) self.renderer.end_rendering() # Save some stuff for next tick self.feedback(controller) return controller
def exec(self, bot) -> SimpleControllerState: car = bot.info.my_car ball = bot.info.ball hits_goal_prediction = predict.will_ball_hit_goal(bot) reach_time = clip(predict.time_till_reach_ball(car, ball), 0, hits_goal_prediction.time - 0.5) reachable_ball = predict.ball_predict(bot, reach_time) self.ball_to_goal_right = self.own_goal_right - reachable_ball.pos self.ball_to_goal_left = self.own_goal_left - reachable_ball.pos self.aim_cone = AimCone(self.ball_to_goal_left, self.ball_to_goal_right) self.aim_cone.draw(bot, reachable_ball.pos, r=200, g=0, b=160) shoot_controls = bot.shoot.with_aiming(bot, self.aim_cone, reach_time) if not bot.shoot.can_shoot: # Go home return bot.drive.go_home(bot) else: return shoot_controls
def with_aiming(self, bot, aim_cone: AimCone, time: float, dodge_hit: bool = True): # aim: | | | | # ball | bad | ok | good | # z pos: | | | | # -----------+-----------+-----------+-----------+ # too high | give | give | wait/ | # | up | up | improve | # -----------+ - - - - - + - - - - - + - - - - - + # medium | give | improve | aerial | # | up | aim | | # -----------+ - - - - - + - - - - - + - - - - - + # soon on | improve | slow | small | # ground | aim | curve | jump | # -----------+ - - - - - + - - - - - + - - - - - + # on ground | improve | fast | fast | # | aim?? | curve | straight | # -----------+ - - - - - + - - - - - + - - - - - + # FIXME if the ball is not on the ground we treat it as 'soon on ground' in all other cases self.controls = SimpleControllerState() self.aim_is_ok = False self.waits_for_fall = False self.ball_is_flying = False self.can_shoot = False self.using_curve = False self.curve_point = None self.ball_when_hit = None car = bot.info.my_car ball_soon = ball_predict(bot, time) car_to_ball_soon = ball_soon.pos - car.pos dot_facing_score = dot(normalize(car_to_ball_soon), normalize(car.forward)) vel_towards_ball_soon = proj_onto_size(car.vel, car_to_ball_soon) is_facing = 0 < dot_facing_score if ball_soon.pos.z < 110 or (ball_soon.pos.z < 475 and ball_soon.vel.z <= 0) or True: #FIXME Always true # The ball is on the ground or soon on the ground if 275 < ball_soon.pos.z < 475 and aim_cone.contains_direction( car_to_ball_soon): # Can we hit it if we make a small jump? vel_f = proj_onto_size(car.vel, xy(car_to_ball_soon)) car_expected_pos = car.pos + car.vel * time ball_soon_flat = xy(ball_soon.pos) diff = norm(car_expected_pos - ball_soon_flat) ball_in_front = dot(ball_soon.pos - car_expected_pos, car.vel) > 0 if bot.do_rendering: bot.renderer.draw_line_3d(car.pos, car_expected_pos, bot.renderer.lime()) bot.renderer.draw_rect_3d(car_expected_pos, 12, 12, True, bot.renderer.lime()) if vel_f > 400: if diff < 150 and ball_in_front: bot.maneuver = SmallJumpManeuver( bot, lambda b: b.info.ball.pos) if 110 < ball_soon.pos.z: # and ball_soon.vel.z <= 0: # The ball is slightly in the air, lets wait just a bit more self.waits_for_fall = True ball_landing = next_ball_landing(bot, ball_soon, size=100) time = time + ball_landing.time ball_soon = ball_predict(bot, time) car_to_ball_soon = ball_soon.pos - car.pos self.ball_when_hit = ball_soon # The ball is on the ground, are we in position for a shot? if aim_cone.contains_direction(car_to_ball_soon) and is_facing: # Straight shot self.aim_is_ok = True self.can_shoot = True if norm(car_to_ball_soon) < 240 + Ball.RADIUS and aim_cone.contains_direction(car_to_ball_soon)\ and vel_towards_ball_soon > 300: bot.drive.start_dodge(bot) offset_point = xy( ball_soon.pos) - 50 * aim_cone.get_center_dir() speed = self._determine_speed(norm(car_to_ball_soon), time) self.controls = bot.drive.towards_point(bot, offset_point, target_vel=speed, slide=True, boost_min=0, can_keep_speed=False) return self.controls elif aim_cone.contains_direction(car_to_ball_soon, math.pi / 5): # Curve shot self.aim_is_ok = True self.using_curve = True self.can_shoot = True offset_point = xy( ball_soon.pos) - 50 * aim_cone.get_center_dir() closest_dir = aim_cone.get_closest_dir_in_cone( car_to_ball_soon) self.curve_point = curve_from_arrival_dir( car.pos, offset_point, closest_dir) self.curve_point.x = clip(self.curve_point.x, -Field.WIDTH / 2, Field.WIDTH / 2) self.curve_point.y = clip(self.curve_point.y, -Field.LENGTH / 2, Field.LENGTH / 2) if dodge_hit and norm(car_to_ball_soon) < 240 + Ball.RADIUS and angle_between(car.forward, car_to_ball_soon) < 0.5\ and aim_cone.contains_direction(car_to_ball_soon) and vel_towards_ball_soon > 300: bot.drive.start_dodge(bot) speed = self._determine_speed(norm(car_to_ball_soon), time) self.controls = bot.drive.towards_point(bot, self.curve_point, target_vel=speed, slide=True, boost_min=0, can_keep_speed=False) return self.controls else: # We are NOT in position! self.aim_is_ok = False pass else: if aim_cone.contains_direction(car_to_ball_soon): self.waits_for_fall = True self.aim_is_ok = True #self.can_shoot = False pass # Allow small aerial (wait if ball is too high) elif aim_cone.contains_direction(car_to_ball_soon, math.pi / 4): self.ball_is_flying = True pass # Aim is ok, but ball is in the air
def run(self, bot) -> SimpleControllerState: car = bot.info.my_car ball = bot.info.ball my_hit_time = predict.time_till_reach_ball(car, ball) shoot_controls = bot.shoot.with_aiming(bot, self.aim_cone, my_hit_time) hit_pos = bot.shoot.ball_when_hit.pos dist = norm(car.pos - hit_pos) closest_enemy, enemy_dist = bot.info.closest_enemy(0.5 * (hit_pos + ball.pos)) if not bot.shoot.can_shoot and is_closer_to_goal_than(car.pos, hit_pos, bot.info.team): # Can't shoot but or at least on the right side: Chase goal_to_ball = normalize(hit_pos - bot.info.opp_goal.pos) offset_ball = hit_pos + goal_to_ball * Ball.RADIUS * 0.9 enemy_hit_time = predict.time_till_reach_ball(closest_enemy, ball) enemy_hit_pos = predict.ball_predict(bot, enemy_hit_time).pos if enemy_hit_time < 1.5 * my_hit_time: self.temp_utility_desire_boost -= bot.info.dt if bot.do_rendering: bot.renderer.draw_line_3d(closest_enemy.pos, enemy_hit_pos, bot.renderer.red()) return bot.drive.home(bot) if bot.do_rendering: bot.renderer.draw_line_3d(car.pos, offset_ball, bot.renderer.yellow()) return bot.drive.towards_point(bot, offset_ball, target_vel=2200, slide=False, boost_min=0) elif len(bot.info.teammates) == 0 and not bot.shoot.aim_is_ok and hit_pos.y * -bot.info.team_sign > 4250 and abs(hit_pos.x) > 900 and not dist < 420: # hit_pos is an enemy corner and we are not close: Avoid enemy corners in 1s and just wait enemy_to_ball = normalize(hit_pos - closest_enemy.pos) wait_point = hit_pos + enemy_to_ball * enemy_dist # a point 50% closer to the center of the field wait_point = lerp(wait_point, ball.pos + Vec3(0, bot.info.team_sign * 3000, 0), 0.5) if bot.do_rendering: bot.renderer.draw_line_3d(car.pos, wait_point, bot.renderer.yellow()) return bot.drive.towards_point(bot, wait_point, norm(car.pos - wait_point), slide=False, can_keep_speed=True, can_dodge=False) elif bot.shoot.can_shoot: # Shoot ! if bot.do_rendering: self.aim_cone.draw(bot, bot.shoot.ball_when_hit.pos, r=0, b=0) if bot.shoot.using_curve: rendering.draw_bezier(bot, [car.pos, bot.shoot.curve_point, hit_pos]) return shoot_controls else: # We can't shoot at goal reliably # How about a shot to the corners then? corners = [ Vec3(-Field.WIDTH2, -bot.info.team_sign * Field.LENGTH2, 0), Vec3(Field.WIDTH2, -bot.info.team_sign * Field.LENGTH2, 0), ] for corner in corners: ctrls = bot.shoot.towards(bot, corner, bot.info.my_car.reach_ball_time) if bot.shoot.can_shoot: self.aim_cone.draw(bot, bot.shoot.ball_when_hit.pos, b=0) if bot.shoot.using_curve: rendering.draw_bezier(bot, [car.pos, bot.shoot.curve_point, hit_pos]) return ctrls enemy_to_ball = normalize(xy(ball.pos - closest_enemy.pos)) ball_to_my_goal = normalize(xy(bot.info.own_goal.pos - ball.pos)) dot_threat = dot(enemy_to_ball, ball_to_my_goal) # 1 = enemy is in position, -1 = enemy is NOT in position if car.boost <= 10 and ball.pos.y * bot.info.team_sign < 0 and dot_threat < 0.15: collect_center = ball.pos.y * bot.info.team_sign <= 0 collect_small = closest_enemy.pos.y * bot.info.team_sign <= 0 or enemy_dist < 900 pads = filter_pads(bot, bot.info.big_boost_pads, big_only=not collect_small, enemy_side=False, center=collect_center) bot.maneuver = CollectClosestBoostManeuver(bot, pads) # return home-ish return bot.drive.stay_at(bot, lerp(bot.info.own_goal.pos, ball.pos, 0.2), ball.pos)
def exec(self, bot): pred_ball = predict.ball_predict(bot, bot.info.my_car.reach_ball_time) # On a scale from 0 to 1, how much is this a clear? clear01 = clip01( norm(bot.info.opp_goal.pos - pred_ball.pos) / Field.LENGTH)**2 ts = bot.info.team_sign right = lerp(bot.info.opp_goal.right_post, Vec3(ts * Field.WIDTH2, ts * (Field.LENGTH2 + 300), 0), clear01) left = lerp(bot.info.opp_goal.left_post, Vec3(-ts * Field.WIDTH2, ts * (Field.LENGTH2 + 300), 0), clear01) ball_to_right = right - pred_ball.pos ball_to_left = left - pred_ball.pos aim_cone = AimCone(ball_to_right, ball_to_left) shot_ctrls = bot.shoot.with_aiming(bot, aim_cone, bot.info.my_car.reach_ball_time) if bot.do_rendering: if bot.shoot.can_shoot: aim_cone.draw(bot, bot.shoot.ball_when_hit.pos, b=0, r=0) if not bot.shoot.can_shoot: # We can't shoot on target if len(bot.info.teammates) != 0: # Consider passing for mate in bot.info.teammates: point_in_front_of_mate = lerp(mate.pos, bot.info.opp_goal.pos, 0.5) shot_ctrls = bot.shoot.towards( bot, point_in_front_of_mate, bot.info.my_car.reach_ball_time) if bot.shoot.can_shoot: if bot.do_rendering: rendering.draw_cross(bot, point_in_front_of_mate, bot.renderer.green()) return shot_ctrls # Atba with bias I guess if bot.do_rendering: bot.renderer.draw_line_3d(bot.info.my_car.pos, pred_ball.pos, bot.renderer.red()) return bot.shoot.any_touch(bot, bot.info.my_car.reach_ball_time) # # We are out of position, start rotating back # own_goal = lerp(bot.info.own_goal.pos, bot.info.ball.pos, 0.5) # return bot.drive.towards_point( # bot, # own_goal, # target_vel=1460, # slide=False, # boost_min=0, # can_keep_speed=True # ) else: # Shoot! if bot.shoot.using_curve and bot.do_rendering: rendering.draw_bezier(bot, [ bot.info.my_car.pos, bot.shoot.curve_point, bot.shoot.ball_when_hit.pos ]) return shot_ctrls