< Summary

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

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
CostBasedAssignment(...)0%2100%
Assign(...)0%72800%

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
 022  public CostBasedAssignment(CostDelegate costFunction, AssignDelegate assignFunction) {
 023    _costFunction = costFunction;
 024    _assignFunction = assignFunction;
 025  }
 26
 27  // Run the assignment algorithm and assign the hierarchical objects.
 28  public override List<AssignmentItem> Assign(IReadOnlyList<IHierarchical> first,
 029                                              IReadOnlyList<IHierarchical> second) {
 030    int numFirst = first.Count;
 031    int numSecond = second.Count;
 032    if (numFirst == 0 || numSecond == 0) {
 033      return new List<AssignmentItem>();
 34    }
 35
 36    // Find all pairwise assignment costs.
 037    var assignmentCosts = new float[numFirst * numSecond];
 038    for (int firstIndex = 0; firstIndex < numFirst; ++firstIndex) {
 039      for (int secondIndex = 0; secondIndex < numSecond; ++secondIndex) {
 040        float cost = _costFunction(first[firstIndex], second[secondIndex]);
 041        float clampedCost = Mathf.Clamp(cost, -_maxCost, _maxCost);
 042        if (cost != clampedCost) {
 043          Debug.LogWarning($"Assignment cost was clamped from {cost} to {clampedCost}.");
 044        }
 045        assignmentCosts[firstIndex * numSecond + secondIndex] = clampedCost;
 046      }
 047    }
 48
 49    // Solve the assignment problem.
 050    var assignedFirstIndices = new int[numFirst];
 051    var assignedSecondIndices = new int[numFirst];
 052    Plugin.StatusCode status =
 53        _assignFunction(numFirst, numSecond, assignmentCosts, assignedFirstIndices,
 54                        assignedSecondIndices, out int numAssignments);
 055    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
 063    var assignments = new List<AssignmentItem>();
 064    for (int i = 0; i < numAssignments; ++i) {
 065      int firstIndex = assignedFirstIndices[i];
 066      int secondIndex = assignedSecondIndices[i];
 067      assignments.Add(
 68          new AssignmentItem { First = first[firstIndex], Second = second[secondIndex] });
 069    }
 070    return assignments;
 071  }
 72}