diff --git a/src/software/ai/evaluation/defender_assignment.cpp b/src/software/ai/evaluation/defender_assignment.cpp index 6358f08a2f..3f0b64b995 100644 --- a/src/software/ai/evaluation/defender_assignment.cpp +++ b/src/software/ai/evaluation/defender_assignment.cpp @@ -3,6 +3,7 @@ #include "software/geom/algorithms/convex_angle.h" #include "software/geom/algorithms/distance.h" #include "software/geom/algorithms/intersection.h" +#include "software/geom/algorithms/intersects.h" #include "software/math/math_functions.h" std::vector getAllDefenderAssignments( @@ -45,8 +46,26 @@ std::vector getAllDefenderAssignments( Segment(primary_threat_position, filtered_threats.at(i).robot.position()); double threat_rating = static_cast(filtered_threats.size()) - i; passing_lanes.emplace_back(ShootingLane{lane, threat_rating}); + + Point intercept_point; + if (distance(lane.midPoint(), filtered_threats.at(i).robot.position()) < 1.2 || + intersects(field.friendlyDefenseArea(), lane)) + { + // We can use the midpoint if it is close enough to the receiver to prevent + // a chip pass or the segment goes through the goalie box + intercept_point = lane.midPoint(); + } + else + { + // Otherwise we will position the defender closer to the + intercept_point = + filtered_threats.at(i).robot.position() + + (primary_threat_position - filtered_threats.at(i).robot.position()) + .normalize(1.2); + } + assignments.emplace_back( - DefenderAssignment{PASS_DEFENDER, lane.midPoint(), threat_rating}); + DefenderAssignment{PASS_DEFENDER, intercept_point, threat_rating}); } // Construct goal lanes. diff --git a/src/software/ai/evaluation/enemy_threat.cpp b/src/software/ai/evaluation/enemy_threat.cpp index 3717cbe208..4be8d4bfed 100644 --- a/src/software/ai/evaluation/enemy_threat.cpp +++ b/src/software/ai/evaluation/enemy_threat.cpp @@ -6,6 +6,7 @@ #include "software/ai/evaluation/calc_best_shot.h" #include "software/ai/evaluation/intercept.h" #include "software/ai/evaluation/possession.h" +#include "software/geom/algorithms/contains.h" #include "software/geom/algorithms/intersects.h" #include "software/world/team.h" @@ -42,7 +43,22 @@ std::map, Robot::cmpRobotByID> findAllReceiverPasserPa Segment(passer.position(), receiver.position())); }); - if (!pass_blocked) + bool chick_pass_blocked = std::any_of( + obstacles.begin(), obstacles.end(), + [passer, receiver](const Robot &obstacle) + { + Segment pass_lane = Segment(passer.position(), receiver.position()); + return contains( + Circle(pass_lane.midPoint(), pass_lane.length() / 2.0), + obstacle.position()) // Here we check if the obstacle is + // between the receiver and passer + && contains( + Circle(receiver.position(), 1.2), + obstacle.position()); // Here we check if the obstacle + // is too close to the receiver + }); + + if (!pass_blocked || !chick_pass_blocked) { if (receiver_passer_pairs.count(receiver) > 0) { diff --git a/src/software/ai/evaluation/enemy_threat_test.cpp b/src/software/ai/evaluation/enemy_threat_test.cpp index dd9869d821..3ff62fc3f0 100644 --- a/src/software/ai/evaluation/enemy_threat_test.cpp +++ b/src/software/ai/evaluation/enemy_threat_test.cpp @@ -43,10 +43,11 @@ TEST(FindAllPasserReceiverPairsTest, AngularVelocity::zero(), Timestamp::fromSeconds(0)); Robot friendly_robot_1 = Robot(1, Point(3, 2), Vector(0, 0), Angle::zero(), AngularVelocity::zero(), Timestamp::fromSeconds(0)); - Robot friendly_robot_2 = Robot(2, Point(5, 0), Vector(0, 0), Angle::zero(), + Robot friendly_robot_2 = Robot(2, Point(3, 0), Vector(0, 0), Angle::zero(), AngularVelocity::zero(), Timestamp::fromSeconds(0)); - // Blocks the pass from robot 0 to robot 2 + // Blocks the pass from robot 0 to robot 2, is close enough to robot 2 to prevent a + // chip pass Robot enemy_robot_0 = Robot(0, Point(2, 0), Vector(0, 0), Angle::zero(), AngularVelocity::zero(), Timestamp::fromSeconds(0)); @@ -62,6 +63,33 @@ TEST(FindAllPasserReceiverPairsTest, EXPECT_EQ(result, expected_result); } +TEST(FindAllPasserReceiverPairsTest, + two_passers_one_receiver_with_no_pass_blocked_by_obstacles) +{ + Robot friendly_robot_0 = Robot(0, Point(0, 0), Vector(0, 0), Angle::zero(), + AngularVelocity::zero(), Timestamp::fromSeconds(0)); + Robot friendly_robot_1 = Robot(1, Point(3, 2), Vector(0, 0), Angle::zero(), + AngularVelocity::zero(), Timestamp::fromSeconds(0)); + Robot friendly_robot_2 = Robot(2, Point(5, 0), Vector(0, 0), Angle::zero(), + AngularVelocity::zero(), Timestamp::fromSeconds(0)); + + // Is too far awar from robot 2 to block a chip pass + Robot enemy_robot_0 = Robot(0, Point(2, 0), Vector(0, 0), Angle::zero(), + AngularVelocity::zero(), Timestamp::fromSeconds(0)); + + std::vector all_robots{friendly_robot_0, friendly_robot_1, friendly_robot_2, + enemy_robot_0}; + + auto result = findAllReceiverPasserPairs({friendly_robot_0, friendly_robot_1}, + {friendly_robot_2}, all_robots); + + std::map, Robot::cmpRobotByID> expected_result = { + std::make_pair(friendly_robot_2, + std::vector{friendly_robot_0, friendly_robot_1})}; + + EXPECT_EQ(result, expected_result); +} + TEST(FindAllPasserReceiverPairsTest, all_passes_blocked) { Robot friendly_robot_0 = Robot(0, Point(0, 0), Vector(0, 0), Angle::zero(), @@ -70,7 +98,7 @@ TEST(FindAllPasserReceiverPairsTest, all_passes_blocked) AngularVelocity::zero(), Timestamp::fromSeconds(0)); // Blocks the pass from robot 0 to robot 1 - Robot enemy_robot_0 = Robot(0, Point(2, 0), Vector(0, 0), Angle::zero(), + Robot enemy_robot_0 = Robot(0, Point(4, 0), Vector(0, 0), Angle::zero(), AngularVelocity::zero(), Timestamp::fromSeconds(0)); std::vector all_robots{friendly_robot_0, friendly_robot_1, enemy_robot_0}; @@ -81,6 +109,28 @@ TEST(FindAllPasserReceiverPairsTest, all_passes_blocked) EXPECT_TRUE(result.empty()); } +TEST(FindAllPasserReceiverPairsTest, chip_pass_not_blocked) +{ + Robot friendly_robot_0 = Robot(0, Point(0, 0), Vector(0, 0), Angle::zero(), + AngularVelocity::zero(), Timestamp::fromSeconds(0)); + Robot friendly_robot_1 = Robot(1, Point(5, 0), Vector(0, 0), Angle::zero(), + AngularVelocity::zero(), Timestamp::fromSeconds(0)); + + // Not close enough to robot 1 to block the pass + Robot enemy_robot_0 = Robot(0, Point(2, 0), Vector(0, 0), Angle::zero(), + AngularVelocity::zero(), Timestamp::fromSeconds(0)); + + std::vector all_robots{friendly_robot_0, friendly_robot_1, enemy_robot_0}; + + auto result = + findAllReceiverPasserPairs({friendly_robot_0}, {friendly_robot_1}, all_robots); + + std::map, Robot::cmpRobotByID> expected_result = { + std::make_pair(friendly_robot_1, std::vector{friendly_robot_0})}; + + EXPECT_EQ(result, expected_result); +} + TEST(FindAllPasserReceiverPairsTest, receiver_with_multiple_passers) { Robot friendly_robot_0 = Robot(0, Point(0, 0), Vector(0, 0), Angle::zero(), @@ -152,7 +202,7 @@ TEST(GetNumPassesToRobotTest, one_simple_pass_to_robot_with_no_obstacles) EXPECT_EQ(passer.value(), friendly_robot_0); } -// TODO: Re-enable as part of https://github.com/UBC-Thunderbots/Software/issues/642 +// TODO: Re-enable as part of + // TEST(GetNumPassesToRobotTest, two_passes_around_a_single_obstacle) //{ // Robot friendly_robot_0 = Robot(0, Point(0, 0), Vector(0, 0), Angle::zero(),