public GunAmmoGroup(GunGroup guns, AmmoBox[] ammo, int firings)
 {
     this.Guns = guns;
     this.Ammo = ammo;
     this.Firings = firings;
 }
        private static GunAmmoGroup[][] GetAmmoGroupings(GunGroup[][] gunCombos, IEnumerable<AmmoBox> boxes)
        {
            double smallestDemand = gunCombos[0].Min(o => o.DemandPerGun);      // only need to look at one of the combos, because each combo has all guns
            double smallestCaliber = gunCombos[0].Min(o => o.Caliber);

            // Commit the boxes to an array that will be reused for each combination of guns
            AmmoBox[] sortedBoxes = boxes.
                Where(o => o.QuantityMax >= smallestDemand && Math1D.Min(o.ScaleActual.X, o.ScaleActual.Y, o.ScaleActual.Z) >= smallestCaliber).        // only keep what will fit the smallest gun
                OrderByDescending(o => o.QuantityMax).      // order the boxes descending so that the largest gets assigned first
                ToArray();

            // Get the distance between each ammo box and each gun
            Tuple<long, long, double>[] ammo_gun_distance = gunCombos[0].
                SelectMany(o => o.Guns).
                SelectMany(gun => sortedBoxes.Select(box => Tuple.Create(box.Token, gun.Token, (box.Position - gun.Position).Length))).
                ToArray();

            return gunCombos.
                AsParallel().
                Select(o => GetAmmoGroupings_Assign(o, sortedBoxes, ammo_gun_distance)).       // Assign all the boxes to this arrangment of guns
                ToArray();
        }
        private static Tuple<double, double> Get_Capacity_Firings(List<AmmoBox> boxes, GunGroup gun)
        {
            double capacity = 0;
            double firings = 0;

            if (boxes.Count > 0)
            {
                capacity = boxes.Sum(p => p.QuantityMax);
                firings = capacity / gun.DemandTotal;
            }

            return Tuple.Create(capacity, firings);
        }
        private static GunGroup[][] ConvertSets(int[][][] combos, ProjectileGun[] guns, Tuple<double, double>[][] caliberRanges, Func<Tuple<double, double>, double> caliberFunc)
        {
            GunGroup[][] retVal = new GunGroup[combos.Length][];

            for (int i = 0; i < combos.Length; i++)
            {
                GunGroup[] set = new GunGroup[combos[i].Length];

                for (int j = 0; j < combos[i].Length; j++)
                {
                    double caliber = caliberFunc(caliberRanges[i][j]);

                    ProjectileGun[] gunSet = combos[i][j].
                        Select(o => guns[o]).
                        ToArray();

                    double demand = GetAmmoVolume(caliber);

                    set[j] = new GunGroup(gunSet, caliber, demand);
                }

                retVal[i] = set;
            }

            return retVal;
        }