< Summary

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

Metrics

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

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,
 016                                                        in IReadOnlyList<Threat> threats) {
 017    List<IAssignment.AssignmentItem> assignments = new List<IAssignment.AssignmentItem>();
 18
 019    List<Interceptor> assignableInterceptors = IAssignment.GetAssignableInterceptors(interceptors);
 020    if (assignableInterceptors.Count == 0) {
 021      Debug.LogWarning("No assignable interceptors found.");
 022      return assignments;
 23    }
 24
 025    List<Threat> activeThreats = IAssignment.GetActiveThreats(threats);
 026    if (activeThreats.Count == 0) {
 027      Debug.LogWarning("No active threats found.");
 028      return assignments;
 29    }
 30
 31    // Find all pairwise assignment costs.
 032    float[] assignmentCosts = new float[assignableInterceptors.Count * activeThreats.Count];
 033    for (int interceptorIndex = 0; interceptorIndex < assignableInterceptors.Count;
 034         ++interceptorIndex) {
 035      Interceptor interceptor = assignableInterceptors[interceptorIndex];
 36
 37      // The speed decays exponentially with the travelled distance and with the bearing change.
 038      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));
 043      float angleTimeConstant = interceptor.staticConfig.LiftDragConfig?.LiftDragRatio ?? 1;
 44      // During the turn, the minimum radius dictates the minimum distance needed to make the turn.
 045      float minTurningRadius = (float)(interceptor.GetVelocity().sqrMagnitude /
 46                                       interceptor.CalculateMaxNormalAcceleration());
 47
 048      for (int threatIndex = 0; threatIndex < activeThreats.Count; ++threatIndex) {
 049        Threat threat = activeThreats[threatIndex];
 050        Vector3 directionToThreat = threat.GetPosition() - interceptor.GetPosition();
 051        float distanceToThreat = directionToThreat.magnitude;
 052        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.
 057        float fractionalSpeed = Mathf.Exp(
 58            -((distanceToThreat + angleToThreat * minTurningRadius) / distanceTimeConstant +
 59              angleToThreat / angleTimeConstant));
 60        // Prevent division by zero.
 061        fractionalSpeed = Mathf.Max(fractionalSpeed, _minFractionalSpeed);
 062        float cost = (float)interceptor.GetSpeed() / fractionalSpeed;
 063        assignmentCosts[interceptorIndex * activeThreats.Count + threatIndex] =
 64            Mathf.Min(cost, _maxCost);
 065      }
 066    }
 67
 68    // Solve the assignment problem.
 069    int[] assignedInterceptorIndices = new int[assignableInterceptors.Count];
 070    int[] assignedThreatIndices = new int[assignableInterceptors.Count];
 071    Plugin.StatusCode status = Assignment.Assignment_EvenAssignment_Assign(
 72        assignableInterceptors.Count, activeThreats.Count, assignmentCosts,
 73        assignedInterceptorIndices, assignedThreatIndices, out int numAssignments);
 074    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
 079    for (int i = 0; i < numAssignments; ++i) {
 080      int interceptorIndex = assignedInterceptorIndices[i];
 081      int threatIndex = assignedThreatIndices[i];
 082      assignments.Add(new IAssignment.AssignmentItem(assignableInterceptors[interceptorIndex],
 83                                                     activeThreats[threatIndex]));
 084    }
 085    return assignments;
 086  }
 87}