Пример #1
0
 private IndustryNode FindIndustry(string name)
 {
     if (IndustryRootNode == null)
     {
         IndustryRootNode = this.FindRootNode <IndustryNode>();
     }
     return(FindNode(IndustryRootNode, node => node.Name.Trim().Equals(name.Trim(), StringComparison.CurrentCultureIgnoreCase)));
 }
Пример #2
0
        public IndustryCalculatorResult BuildIndustryTree(IndustryTreeCalculationType calculationType)
        {
            Queue <IndustryNode>            queue         = new Queue <IndustryNode>();
            Dictionary <Type, IndustryNode> existingNodes = new Dictionary <Type, IndustryNode>();

            List <IndustryNode> parentNodes = new List <IndustryNode>();

            foreach (var wantedResult in __Results)
            {
                IndustryNode parent;
                if (existingNodes.ContainsKey(wantedResult.ResultType))
                {
                    parent = existingNodes[wantedResult.ResultType];
                    parent.BuildingAmount += wantedResult.MachineAmount;
                }
                else
                {
                    parent = new IndustryNode(wantedResult.ResultType);
                    parent.BuildingAmount = wantedResult.MachineAmount;
                    existingNodes.Add(wantedResult.ResultType, parent);
                    queue.Enqueue(parent);
                    parentNodes.Add(parent);
                }

                parent.NeededProductionAmountPerMinute = parent.BuildingAmount * parent.Product.GetProductionProMinute();
            }


            while (queue.Count != 0)
            {
                //We update all IndustryNodes of the recipe items (creating them if not existing), update their member variables and then enque them. This way once the queue is empty, all have been updated.
                IndustryNode node = queue.Dequeue();

                if (node.Product.isOre())
                {
                    node.BuildingAmount         = 1;
                    node.ProductAmountPerMinute = node.NeededProductionAmountPerMinute;
                    continue;
                }

                //First we recalculate the current buildings BuildingAmount and ProductAmountPerMinute based on NeededProductionAmountPerMinute. We also remember how much it increased so we can update the recipes accordingly.
                double productPerMinutePerBuilding = node.Product.GetProductionProMinute();
                //Updating amount of buildings needed.
                int oldBuildingAmount = node.BuildingAmount;
                switch (calculationType)
                {
                case IndustryTreeCalculationType.Overflow:
                    node.BuildingAmount = (int)Math.Ceiling(node.NeededProductionAmountPerMinute / productPerMinutePerBuilding);
                    break;

                case IndustryTreeCalculationType.Exact:
                    node.BuildingAmount = (int)Math.Ceiling(node.NeededProductionAmountPerMinute / productPerMinutePerBuilding);
                    break;

                case IndustryTreeCalculationType.Underflow:
                    node.BuildingAmount = (int)Math.Max(Math.Floor(node.NeededProductionAmountPerMinute / productPerMinutePerBuilding), 1);
                    break;
                }

                //Updating Production values
                double previousProductAmountPerMinute = node.ProductAmountPerMinute;
                switch (calculationType)
                {
                case IndustryTreeCalculationType.Overflow:
                    break;

                case IndustryTreeCalculationType.Exact:
                    break;

                case IndustryTreeCalculationType.Underflow:
                    break;
                }

                switch (calculationType)
                {
                case IndustryTreeCalculationType.Overflow:
                    node.ProductAmountPerMinute = node.BuildingAmount * productPerMinutePerBuilding;
                    break;

                case IndustryTreeCalculationType.Exact:
                    node.ProductAmountPerMinute = node.NeededProductionAmountPerMinute;
                    break;

                case IndustryTreeCalculationType.Underflow:
                    node.ProductAmountPerMinute = node.BuildingAmount * productPerMinutePerBuilding;
                    break;
                }

                double productAmountPerMinuteIncreasedBy = node.ProductAmountPerMinute - previousProductAmountPerMinute;

                if (calculationType != IndustryTreeCalculationType.Exact && productAmountPerMinuteIncreasedBy == 0)
                {
                    continue;
                }

                //Then for every item needed for this, we calculate how many more we need now.
                foreach (var recipeItemPair in node.ItemsNeeded)
                {
                    Type  itemType     = recipeItemPair.Key;
                    int   amountNeeded = recipeItemPair.Value;
                    IItem item         = Statics.Items[itemType];

                    //Calculating how much more we need to add to this specific node.
                    double amountNeededPerMinuteIncrease = (productAmountPerMinuteIncreasedBy / node.Product.GetProductionAmount()) * amountNeeded;

                    //Finding the right node
                    IndustryNode recipeItemNode;
                    if (existingNodes.ContainsKey(itemType))
                    {
                        //We update it
                        recipeItemNode = existingNodes[itemType];
                        double oldProductionPerMinuteNeeded = recipeItemNode.NeededProductionAmountPerMinute;
                        recipeItemNode.NeededProductionAmountPerMinute += amountNeededPerMinuteIncrease;
                    }
                    else
                    {
                        //We create a new one
                        recipeItemNode = new IndustryNode(itemType);
                        recipeItemNode.NeededProductionAmountPerMinute = amountNeededPerMinuteIncrease;
                        existingNodes.Add(itemType, recipeItemNode);
                    }

                    //We enqueue the node, so it's BuildingAmount and ProductAmountPerMinute, as well as its recipe item get updated
                    queue.Enqueue(recipeItemNode);
                }
            }

            //Resetting parents needed production so you can compare Production to needed production to get sellable quantity
            foreach (var parent in parentNodes)
            {
                parent.NeededProductionAmountPerMinute = 0;
            }

            //Collect all Data
            var allNodes = existingNodes.Values.ToList();
            IndustryCalculatorResult            result          = new IndustryCalculatorResult();
            Dictionary <IIndustryBuilding, int> buildingAmounts = new Dictionary <IIndustryBuilding, int>();

            foreach (var node in allNodes)
            {
                if (node.Product.isOre())
                {
                    result.OreMinDumpPrice += node.Product.GetUnitMinPrice() * node.NeededProductionAmountPerMinute;
                    result.OreMaxDumpPrice += node.Product.GetUnitMaxPrice() * node.NeededProductionAmountPerMinute;
                    //Console.WriteLine("Needing " + sellableAmountPerMinute + " of " + node.Product.GetName());
                    result.OreList.Add(new OreListEntry(node.Product.GetName(), node.NeededProductionAmountPerMinute));
                }
                else
                {
                    double sellableAmountPerMinute = node.ProductAmountPerMinute - node.NeededProductionAmountPerMinute;
                    double minSellPrice            = node.Product.GetUnitMinPrice() * sellableAmountPerMinute;
                    double maxSellPrice            = node.Product.GetUnitMaxPrice() * sellableAmountPerMinute;
                    result.MinSellPriceSum += minSellPrice;
                    result.MaxSellPriceSum += maxSellPrice;
                    result.ItemList.Add(new ItemListEntry(node.Product.GetName(), node.NeededProductionAmountPerMinute, node.Building.GetName(), node.BuildingAmount, minSellPrice, maxSellPrice));
                }

                if (buildingAmounts.ContainsKey(node.Building))
                {
                    buildingAmounts[node.Building] += node.BuildingAmount;
                }
                else
                {
                    buildingAmounts.Add(node.Building, node.BuildingAmount);
                }
            }


            //Convert Buildings list into results BuildingList
            foreach (var buildingsNeededEntry in buildingAmounts)
            {
                string name = buildingsNeededEntry.Key.GetName();
                result.BuildingList.Add(new BuildingListEntry(name, buildingsNeededEntry.Value));
            }

            //Calculating Ore prices
            result.OreAmountPerMinNeeded = 0;
            foreach (var ore in result.OreList)
            {
                result.OreAmountPerMinNeeded += ore.AmountNeededPerMinute;
            }

            result.TechnicallyMaxSellMaxOreBuyPrice = result.MaxSellPriceSum / result.OreAmountPerMinNeeded;
            result.RecommendedMaxOreBuyPrice        = ((result.MinSellPriceSum + result.MaxSellPriceSum) / 2 * 0.8) / result.OreAmountPerMinNeeded;


            result.ProfitBuyingOreRecommendedSellingMax = result.MaxSellPriceSum - (result.RecommendedMaxOreBuyPrice * result.OreAmountPerMinNeeded);
            return(result);
        }