< Summary

Class:CostBasedAssignment
Assembly:bamlab.micromissiles
File(s):/github/workspace/Assets/Scripts/Assignment/CostBasedAssignment.cs
Covered lines:30
Uncovered lines:4
Coverable lines:34
Total lines:72
Line coverage:88.2% (30 of 34)
Covered branches:0
Total branches:0
Covered methods:2
Total methods:2
Method coverage:100% (2 of 2)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
CostBasedAssignment(...)0%110100%
Assign(...)0%8.198085.71%

File(s)

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

#LineLine coverage
 1using System.Collections.Generic;
 2using System.Linq;
 3using UnityEngine;
 4
 5// The cost-based assignment assigns hierarchical objects to each other based on the pairwise costs
 6// between them.
 7public class CostBasedAssignment : AssignmentBase {
 8  // Delegate for determining the cost of an assignment between two hierarchical objects.
 9  public delegate float CostDelegate(IHierarchical first, IHierarchical second);
 10
 11  // Delegate for performing the assignment.
 12  public delegate Plugin.StatusCode AssignDelegate(int numFirst, int numSecond, float[] costs,
 13                                                   int[] assignedFirsts, int[] assignedSeconds,
 14                                                   out int numAssignments);
 15
 16  // Maximum cost to prevent overflow.
 17  private const float _maxCost = 1e12f;
 18
 19  private readonly CostDelegate _costFunction;
 20  private readonly AssignDelegate _assignFunction;
 21
 422  public CostBasedAssignment(CostDelegate costFunction, AssignDelegate assignFunction) {
 223    _costFunction = costFunction;
 224    _assignFunction = assignFunction;
 225  }
 26
 27  // Run the assignment algorithm and assign the hierarchical objects.
 28  public override List<AssignmentItem> Assign(IReadOnlyList<IHierarchical> first,
 1029                                              IReadOnlyList<IHierarchical> second) {
 1030    int numFirst = first.Count;
 1031    int numSecond = second.Count;
 1432    if (numFirst == 0 || numSecond == 0) {
 433      return new List<AssignmentItem>();
 34    }
 35
 36    // Find all pairwise assignment costs.
 637    var assignmentCosts = new float[numFirst * numSecond];
 15938    for (int firstIndex = 0; firstIndex < numFirst; ++firstIndex) {
 28739      for (int secondIndex = 0; secondIndex < numSecond; ++secondIndex) {
 6340        float cost = _costFunction(first[firstIndex], second[secondIndex]);
 6341        float clampedCost = Mathf.Clamp(cost, -_maxCost, _maxCost);
 6342        if (cost != clampedCost) {
 043          Debug.LogWarning($"Assignment cost was clamped from {cost} to {clampedCost}.");
 044        }
 6345        assignmentCosts[firstIndex * numSecond + secondIndex] = clampedCost;
 6346      }
 4947    }
 48
 49    // Solve the assignment problem.
 650    var assignedFirstIndices = new int[numFirst];
 651    var assignedSecondIndices = new int[numFirst];
 652    Plugin.StatusCode status =
 53        _assignFunction(numFirst, numSecond, assignmentCosts, assignedFirstIndices,
 54                        assignedSecondIndices, out int numAssignments);
 655    if (status != Plugin.StatusCode.StatusOk) {
 056      Debug.LogError(
 57          $"Failed to run the assignment with status code {status}. " +
 58          $"Number of first: {numFirst}, number of second: {numSecond}, " +
 59          $"minimum cost: {assignmentCosts.Min()}, maximum cost: {assignmentCosts.Max()}.");
 060      return new List<AssignmentItem>();
 61    }
 62
 663    var assignments = new List<AssignmentItem>();
 15964    for (int i = 0; i < numAssignments; ++i) {
 4965      int firstIndex = assignedFirstIndices[i];
 4966      int secondIndex = assignedSecondIndices[i];
 4967      assignments.Add(
 68          new AssignmentItem { First = first[firstIndex], Second = second[secondIndex] });
 4969    }
 670    return assignments;
 1071  }
 72}