< Summary

Class:MaxSpeedAssignment
Assembly:bamlab.micromissiles
File(s):/github/workspace/Assets/Scripts/Assignment/MaxSpeedAssignment.cs
Covered lines:39
Uncovered lines:2
Coverable lines:41
Total lines:87
Line coverage:95.1% (39 of 41)
Covered branches:0
Total branches:0
Covered methods:1
Total methods:1
Method coverage:100% (1 of 1)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Assign(...)0%15.0415094.23%

File(s)

/github/workspace/Assets/Scripts/Assignment/MaxSpeedAssignment.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using UnityEngine;
 4
 5// The maximum speed assignment class assigns interceptors to the threats to maximize the intercept
 6// speed by defining a cost of the assignment equal to the speed lost for the maneuver.
 7public class MaxSpeedAssignment : IAssignment {
 8  // Minimum fractional speed to prevent division by zero.
 9  private const float _minFractionalSpeed = 1e-6f;
 10
 11  // Maximum cost to prevent overflow.
 12  private const float _maxCost = 1e12f;
 13
 14  // Assign a threat to each interceptor that has not been assigned a threat yet.
 15  public IEnumerable<IAssignment.AssignmentItem> Assign(in IReadOnlyList<Interceptor> interceptors,
 516                                                        in IReadOnlyList<Threat> threats) {
 517    List<IAssignment.AssignmentItem> assignments = new List<IAssignment.AssignmentItem>();
 18
 519    List<Interceptor> assignableInterceptors = IAssignment.GetAssignableInterceptors(interceptors);
 720    if (assignableInterceptors.Count == 0) {
 221      Debug.LogWarning("No assignable interceptors found.");
 222      return assignments;
 23    }
 24
 325    List<Threat> activeThreats = IAssignment.GetActiveThreats(threats);
 426    if (activeThreats.Count == 0) {
 127      Debug.LogWarning("No active threats found.");
 128      return assignments;
 29    }
 30
 31    // Find all pairwise assignment costs.
 232    float[] assignmentCosts = new float[assignableInterceptors.Count * activeThreats.Count];
 1033    for (int interceptorIndex = 0; interceptorIndex < assignableInterceptors.Count;
 1234         ++interceptorIndex) {
 635      Interceptor interceptor = assignableInterceptors[interceptorIndex];
 36
 37      // The speed decays exponentially with the travelled distance and with the bearing change.
 638      float distanceTimeConstant =
 39          2 * (interceptor.staticConfig.BodyConfig?.Mass ?? 0) /
 40          ((float)Constants.CalculateAirDensityAtAltitude(interceptor.GetPosition().y) *
 41           (interceptor.staticConfig.LiftDragConfig?.DragCoefficient ?? 0) *
 42           (interceptor.staticConfig.BodyConfig?.CrossSectionalArea ?? 0));
 643      float angleTimeConstant = interceptor.staticConfig.LiftDragConfig?.LiftDragRatio ?? 1;
 44      // During the turn, the minimum radius dictates the minimum distance needed to make the turn.
 645      float minTurningRadius = (float)(interceptor.GetVelocity().sqrMagnitude /
 46                                       interceptor.CalculateMaxNormalAcceleration());
 47
 5748      for (int threatIndex = 0; threatIndex < activeThreats.Count; ++threatIndex) {
 1549        Threat threat = activeThreats[threatIndex];
 1550        Vector3 directionToThreat = threat.GetPosition() - interceptor.GetPosition();
 1551        float distanceToThreat = directionToThreat.magnitude;
 1552        float angleToThreat =
 53            Vector3.Angle(interceptor.GetVelocity(), directionToThreat) * Mathf.Deg2Rad;
 54
 55        // The fractional speed is the product of the fractional speed after traveling the distance
 56        // and of the fractional speed after turning.
 1557        float fractionalSpeed = Mathf.Exp(
 58            -((distanceToThreat + angleToThreat * minTurningRadius) / distanceTimeConstant +
 59              angleToThreat / angleTimeConstant));
 60        // Prevent division by zero.
 1561        fractionalSpeed = Mathf.Max(fractionalSpeed, _minFractionalSpeed);
 1562        float cost = (float)interceptor.GetSpeed() / fractionalSpeed;
 1563        assignmentCosts[interceptorIndex * activeThreats.Count + threatIndex] =
 64            Mathf.Min(cost, _maxCost);
 1565      }
 666    }
 67
 68    // Solve the assignment problem.
 269    int[] assignedInterceptorIndices = new int[assignableInterceptors.Count];
 270    int[] assignedThreatIndices = new int[assignableInterceptors.Count];
 271    Plugin.StatusCode status = Assignment.Assignment_EvenAssignment_Assign(
 72        assignableInterceptors.Count, activeThreats.Count, assignmentCosts,
 73        assignedInterceptorIndices, assignedThreatIndices, out int numAssignments);
 274    if (status != Plugin.StatusCode.StatusOk) {
 075      Debug.Log($"Failed to assign the interceptors to the threats with status code {status}.");
 076      return assignments;
 77    }
 78
 2279    for (int i = 0; i < numAssignments; ++i) {
 680      int interceptorIndex = assignedInterceptorIndices[i];
 681      int threatIndex = assignedThreatIndices[i];
 682      assignments.Add(new IAssignment.AssignmentItem(assignableInterceptors[interceptorIndex],
 83                                                     activeThreats[threatIndex]));
 684    }
 285    return assignments;
 586  }
 87}