protected virtual void OnFlowChanged(MeasurementChangedEventArgs e) { FlowChanged?.Invoke(this, e); }
private void FixProductionFlow() { var rawData = Configuration.Instance.RawData; var baseItems = new Dictionary <BaseProducibleObject, WorkspaceProducibleItem>(); foreach (var src in ExistingSources) { baseItems.GetOrCreate(src.MyItem, () => new WorkspaceProducibleItem { Item = src.MyItem }).Balance = float.PositiveInfinity; } foreach (var dst in WantedResults) { baseItems.GetOrCreate(dst.MyItem, () => new WorkspaceProducibleItem { Item = dst.MyItem }).Balance -= dst.Amount; } Dictionary <BaseProducibleObject, WorkspaceProducibleItem> roundResults; int nrounds = 100; do { roundResults = new Dictionary <BaseProducibleObject, WorkspaceProducibleItem>(baseItems); //Step 1: balance all existing nodes var toRemove = new List <BaseFlowNode>(); foreach (var node in ProductionNodes) { var needed = (int)Math.Ceiling(node.Results.Max(x => - roundResults.GetOrDefault(x.RealItem, () => new WorkspaceProducibleItem()).Balance / x.BaseRate)); if (node is Recipe r) { r.Producers = needed; } if (needed == 0) { toRemove.Add(node); continue; } foreach (var egress in node.Results) { var item = roundResults.GetOrCreate(egress.RealItem, () => new WorkspaceProducibleItem { Item = egress.RealItem }); item.Producers.Add(node); item.Balance += egress.Rate; } foreach (var ingress in node.Sources) { var item = roundResults.GetOrCreate(ingress.RealItem, () => new WorkspaceProducibleItem { Item = ingress.RealItem }); item.Consumers.Add(node); item.Balance -= ingress.Rate; } } foreach (var n in toRemove) { ProductionNodes.Remove(n); } //Step 2: add more nodes foreach (var neededItem in roundResults.Where(x => x.Value.Balance < 0)) { var possibleRecipies = rawData.Recipes.Where(x => x.Value.HasResult(neededItem.Key)).ToArray(); _selectedRecipies.TryGetValue(neededItem.Key, out var selectedRecipe); if (!possibleRecipies.Any()) { var satisfier = new ManualItemSource(neededItem.Key); ProductionNodes.Add(satisfier); } else if (possibleRecipies.Length == 1 || selectedRecipe != null) { var recipe = selectedRecipe ?? possibleRecipies.First().Value; var satisfier = new Recipe(recipe); ProductionNodes.Add(satisfier); } else { var selector = new SelectRecipe(possibleRecipies.Select(x => x.Value), neededItem.Key); ProductionNodes.Add(selector); } } } while (roundResults.Any(x => x.Value.Balance < 0) && nrounds-- > 0); Application.Current.Dispatcher.Invoke(() => { Items.Clear(); foreach (var item in roundResults) { foreach (var ingress in item.Value.Consumers) { foreach (var egress in item.Value.Producers) { var edge = new ProducibleItem(egress.Results.First(x => x.RealItem.Equals(item.Key)), ingress.Sources.First(x => x.RealItem.Equals(item.Key)), item.Key); Items.Add(edge); } } } }); /*var rawData = Configuration.Instance.RawData; * var unsatisfied = new HashSet<BaseProducibleObject>( * _satisfierNodes.SelectMany(x => x.Value.Sources.Select(ingress => ingress.RealItem)) * .Concat(WantedResults.Select(w => w.MyItem)) * .Except(_satisfierNodes.Keys) * .Except(ExistingSources.Select(x => x.MyItem)) * ); * while (unsatisfied.Any()) * { * var result = unsatisfied.First(); * unsatisfied.Remove(result); * var possibleRecipies = rawData.Recipes.Where(x => x.Value.HasResult(result)).ToArray(); * _selectedRecipies.TryGetValue(result, out var selectedRecipe); * if (!possibleRecipies.Any()) * { * var satisfier = new ManualItemSource(result); * ProductionNodes.Add(satisfier); * //Bind(satisfier); * _satisfierNodes[result] = satisfier; * } * else if (possibleRecipies.Length == 1 || selectedRecipe != null) * { * var recipe = selectedRecipe ?? possibleRecipies.First().Value; * var satisfier = new Recipe(recipe); * ProductionNodes.Add(satisfier); * foreach (var r in recipe.CurrentMode.Results) * { * var res = rawData.Get(r.Value.Type, r.Value.Name); * _satisfierNodes[res] = satisfier; * unsatisfied.Remove(res); * } * * foreach (var r in possibleRecipies.First().Value.CurrentMode.Sources) * { * var res = rawData.Get(r.Value.Type, r.Value.Name); * if (!_satisfierNodes.ContainsKey(res)) * { * unsatisfied.Add(res); * } * } * } * else * { * var selector = new SelectRecipe(possibleRecipies.Select(x => x.Value), result); * ProductionNodes.Add(selector); * //Bind(selector); * _satisfierNodes[result] = selector; * } * } * * Items.Clear(); * foreach (var source in _satisfierNodes) * { * var egress = source.Value.Results.First(x => x.RealItem.Equals(source.Key)); * foreach (var dest in _satisfierNodes.Values.SelectMany(x => x.Sources?.Where(ingress => ingress.RealItem.Equals(source.Key)) ?? new RecipeIO[0])) * { * var edge = new ProducibleItem(egress, dest, source.Key); * Items.Add(edge); * } * }*/ FlowChanged?.Invoke(this, EventArgs.Empty); }