/// <summary> /// This method is called by the game whenever our robot has scanned another robot by turning the radar. /// Note: Our radar is turning around forever at maximum speed, so this event is called as soon as the /// radar "hits" another robot. /// </summary> /// <param name="scannedRobotEvent">The scanned robot event containing data about the scanned robot.</param> public override void OnScannedRobot(ScannedRobotEvent scannedRobotEvent) { // Exit this method, if the scanned robot is another sentry robot if (scannedRobotEvent.IsSentryRobot) { return; } // Get the distance from our robot to the scanned robot double distance = scannedRobotEvent.Distance; // Calculate the angle in radians to the scanned robot. // Angle = our robot's heading (angle) + the bearing (delta angle) to the scanned robot. double angle = HeadingRadians + scannedRobotEvent.BearingRadians; // Prepare an entry with scanned robot data that we can store in our scanned data map ScannedRobotData robotData = new ScannedRobotData(); // Store the name of the scanned robot robotData.name = scannedRobotEvent.Name; // Store the time when the robot was scanned robotData.time = scannedRobotEvent.Time; // Calculate and store the x coordinate of the scanned robot (using the Robocode coordinate system) robotData.x = X + Math.Sin(angle) * distance; // Calculate and store the y coordinate of the scanned robot (using the Robocode coordinate system) robotData.y = Y + Math.Cos(angle) * distance; // Store the entry of scanned robot entry in our map over scanned robot data. // We use the name of the robot as the key for accessing the scanned data for that particular robot later scannedRobotData.Remove(robotData.name); scannedRobotData.Add(robotData.name, robotData); }
/// <summary> /// This method is called by the game whenever another robot dies. /// </summary> /// <param name="robotDeathEvent">The robot death event containing data about the robot that died.</param> public override void OnRobotDeath(RobotDeathEvent robotDeathEvent) { // Remove the scanned robot data for the robot that died. // This data is useless now, and will only confuse our robot if it stays in our scanned robot data. scannedRobotData.Remove(robotDeathEvent.Name); // Remove our global target, if our target was the robot that died, but only if we have a current target if (target != null && target.name.Equals(robotDeathEvent.Name)) { target = null; } }
/// <summary> /// This method is called by the game before each turn with the current status of our robot. /// </summary> /// <param name="statusEvent">The status event containing status data for our robot.</param> public override void OnStatus(StatusEvent statusEvent) { // 'newTarget' is used for selecting our new target to fire at. // Set this to null here, which means that we have no target... yet! ScannedRobotData newTarget = null; // Prepara a list for containing all scanned robot data. List <ScannedRobotData> currentScanData = new List <ScannedRobotData>(); // Add scanned robot data that is not too old. When data is more than 360 / 45 degrees = 8 turns old, // our radar should retrieve new information about a particular robot, unless it has died or is // out of the scan radius (1200 units). Anyways, the robot will probably have moved far ways since then. foreach (ScannedRobotData robotData in scannedRobotData.Values) { // Add entry if the the delta time (scanned event time - status event time) is less than or equal to 8 turns if (statusEvent.Time - robotData.time <= 8) { currentScanData.Add(robotData); } } // Now, make a copy of current scan data that should contain target candidates List <ScannedRobotData> targetCandidates = new List <ScannedRobotData>(currentScanData); // Prepare a new list for containing scanned robot data, but only with robots List <ScannedRobotData> newCurrentScanData = new List <ScannedRobotData>(); // Add all target candidates that are inside our sentry robot's attack range as we // will not be able to harm robots outside this range with our gun fire (is a game rule). foreach (ScannedRobotData robotData in currentScanData) { // Add robot data if its location is inside the sentry attack range if (IsInsideSentryAttackRange(robotData.x, robotData.y)) { newCurrentScanData.Add(robotData); } } // Save the new list containing robot scan data as the current robot scan data list currentScanData = newCurrentScanData; // If we don't have any target candidates, we have no candidates to fire at. // However, we will then use the current scan data for moving out robot as close to the nearest robot // outside the sentry robot's attack range, so we have a better chance to hit it when it moves too // close to the border. if (targetCandidates.Count == 0) { targetCandidates = new List <ScannedRobotData>(currentScanData); } // Now, pick the new target robot among the target candidates based on how far those are to our robot. // Pick the robot closest to our robot. double shortestDistance = double.MaxValue; // Initialize shortest distance seen, to maximum value foreach (ScannedRobotData robotData in currentScanData) { // Calculate the distance to the robot based on the hypotenuse (Pythagoras) double distance = DistanceTo(robotData.x, robotData.y); // Check if the distance is shorter than shortest distance calculated so far if (distance < shortestDistance) { // If the distance is shorter then save the calculated distance as the new shortest distance shortestDistance = distance; // Save the robot data as our new target robot newTarget = robotData; } } // Check if we got a new target robot if (newTarget != null) { // We got a new target robot.. // Calculate the target angle of the robot double targetAngle = Math.Atan2(newTarget.x - X, newTarget.y - Y); // Normalize the target angle so that the angle is kept within the range [0, PI[ targetAngle = Utils.NormalAbsoluteAngle(targetAngle); // Calculate the delta gun angle, i.e. how much of robot should be moved to the right. double deltaGunAngle = Utils.NormalRelativeAngle(targetAngle - GunHeadingRadians); // Set the gun to turn right the number of radians stored in the calculated delta gun angle. // Note: The setTurnGunRightRadians() will first be executed, when the execute() method is called. // If the delta gun angle is negative, it will automatically be moved in the opposite direction. SetTurnGunRightRadians(deltaGunAngle); // Check that the radar turn has almost completed (has less than 1 degrees left to turn) and // that the target robot is inside the entry attack range. if (RadarTurnRemaining < 1 && IsInsideSentryAttackRange(newTarget.x, newTarget.y)) { // Calculate the fire power we should use when firing at our target.. // We want to use the maximum bullet power 3, when the target is within 100 units and // the bullet power should become lesser the longer the distance is to our target. // Hence, we calculate the fire power as 3 * 100 / distance to target. double firePower = 300 / DistanceTo(newTarget.x, newTarget.y); // Set our gun to fire with the calculated amount of fire power. // Note: If the fire power is less than the minimum fire power 0.1 the gun will not fire. // If the fire power is greater than the maximum fire power 3, then gun will use 3 as fire power. SetFire(firePower); } // Paint a circle on our current target (debugging graphics) PaintCircle(newTarget.x, newTarget.y); } // Set our new target as our new "global" target, so that other methods can use it this.target = newTarget; }