//find which materials are used by a crafter and add back the passed-in value from the inventory
        //once again, it is assumed the inventory has been reduced to 1 material per craft already
        private static void UnRemoveCrafterMaterials(Crafters crafter, int countToUnremove)
        {
            var usedMaterials = GetMaterialsAffectedByCrafter(crafter);

            foreach (var mat in usedMaterials)
            {
                _craftingInventory[mat] += countToUnremove;
            }
        }
        //recursive function to find/build the best crafting path for a given crafter (baseCrafter, the dictionary key)
        //second parameter is the one being evaluated during each call of the method.
        //we're going to remove materials from the inventory, add the crafter to the crafting path list, and then do the same check until we can craft anything else.
        //once we hit the bottom, see if it provides a better count than the existing one for the base crafter. if it does, save it.
        //finally, because most of the time this will not be the last crafter being evaluated, we need to remove the crafter from the list and add the materials used back to the inventory.
        //this is a long-winded way to say I'm basically pushing and popping crafters and materials used for a given step
        private static void CalculateCraftingPaths(Crafters baseCrafter, Crafters currentCrafter)
        {
            //identify which materials(columns) are affected by the craft
            List <Materials> usedMaterials = GetMaterialsAffectedByCrafter(currentCrafter);
            int lowestCount = Int32.MaxValue;

            //find the material with the lowest count that is used by the craft (this will be the most we can craft for a given crafter at a given point)
            foreach (var mat in usedMaterials)
            {
                if (_craftingInventory[mat] < lowestCount)
                {
                    lowestCount = _craftingInventory[mat];
                }
            }

            //add the craft to the list and remove the materials from the inventory
            _recursiveCrafterList.Add(new KeyValuePair <Crafters, int>(currentCrafter, lowestCount));
            RemoveCrafterMaterials(currentCrafter, lowestCount);

            //get crafters that can still make stuff and loop over them
            var remainingCrafters = GetCraftersRemaining();

            if (remainingCrafters.Count > 0)
            {
                foreach (var remainingCraft in remainingCrafters)
                {
                    CalculateCraftingPaths(baseCrafter, remainingCraft);
                }
            }
            //or, if no crafters remain, check to see if this is a new best, save it if it is
            else
            {
                //get the count of both the path being evaluated and the current best
                var listSum    = _recursiveCrafterList.Sum(r => r.Value);
                var currentSum = _crafterCountDictionary[baseCrafter].Sum(d => d.Value);

                //if the path being evaluated is better than the current count, or the current count is the same but uses fewer crafters in the paths, save it as the new best
                if ((listSum > currentSum) || (listSum == currentSum && _recursiveCrafterList.Count() < _crafterCountDictionary[baseCrafter].Count()))
                {
                    _crafterCountDictionary[baseCrafter] = new List <KeyValuePair <Crafters, int> >(_recursiveCrafterList);
                }
            }

            //restore the materials to the inventory for the next loop and remove the craft from the list
            UnRemoveCrafterMaterials(currentCrafter, lowestCount);
            _recursiveCrafterList.RemoveAt(_recursiveCrafterList.Count - 1);
        }
        //return a list of Materials that a given Crafter uses, based on _constCrafterMaterialTable
        private static List <Materials> GetMaterialsAffectedByCrafter(Crafters crafter)
        {
            var materialsList  = new List <Materials>();
            int materialsFound = 0;

            for (int j = 0; j < COUNT_OF_MATERIALS; j++)
            {
                if ((bool)_constCrafterMaterialTable.Rows[(int)crafter][j])
                {
                    materialsFound++;
                    materialsList.Add((Materials)j);

                    //if we have found all the Materials for the craft, break out of the material loop early
                    if (materialsFound == MAX_DIFFERENT_MATERIALS_PER_CRAFT)
                    {
                        break;
                    }
                }
            }

            return(materialsList);
        }