Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Locations #356

Merged
merged 10 commits into from
Nov 18, 2024
2 changes: 1 addition & 1 deletion Yafc.Model/Analysis/Analysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static void ExcludeFromAnalysis<T>(FactorioObject obj) where T : Analysis
}

public static class AnalysisExtensions {
public static bool IsAccessible(this FactorioObject obj) => Milestones.Instance.GetMilestoneResult(obj) != 0;
public static bool IsAccessible(this FactorioObject obj) => Milestones.Instance.GetMilestoneResult(obj)[0];

public static bool IsAccessibleWithCurrentMilestones(this FactorioObject obj) => Milestones.Instance.IsAccessibleWithCurrentMilestones(obj);

Expand Down
40 changes: 1 addition & 39 deletions Yafc.Model/Analysis/AutomationAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,45 +53,7 @@ public override void Compute(Project project, ErrorCollector warnings) {
var dependencies = Dependencies.dependencyList[index];
var automationState = Milestones.Instance.IsAccessibleWithCurrentMilestones(index) ? AutomationStatus.AutomatableNow : AutomationStatus.AutomatableLater;

foreach (var depGroup in dependencies) {
if (!depGroup.flags.HasFlags(DependencyList.Flags.OneTimeInvestment)) {
if (depGroup.flags.HasFlags(DependencyList.Flags.RequireEverything)) {
foreach (var element in depGroup.elements) {
if (state[element] < automationState) {
automationState = state[element];
}
}
}
else {
var localHighest = AutomationStatus.NotAutomatable;

foreach (var element in depGroup.elements) {
if (state[element] > localHighest) {
localHighest = state[element];
}
}

if (localHighest < automationState) {
automationState = localHighest;
}
}
}
else if (automationState == AutomationStatus.AutomatableNow && depGroup.flags == DependencyList.Flags.CraftingEntity) {
// If only character is accessible at current milestones as a crafting entity, don't count the object as currently automatable
bool hasMachine = false;

foreach (var element in depGroup.elements) {
if (element != Database.character?.id && Milestones.Instance.IsAccessibleWithCurrentMilestones(element)) {
hasMachine = true;
break;
}
}

if (!hasMachine) {
automationState = AutomationStatus.AutomatableLater;
}
}
}
automationState = dependencies.IsAutomatable(id => state[id], automationState);

if (automationState == UnknownInQueue) {
automationState = Unknown;
Expand Down
64 changes: 20 additions & 44 deletions Yafc.Model/Analysis/Dependencies.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Yafc.Model;

public interface IDependencyCollector {
void Add(FactorioId[] raw, DependencyList.Flags flags);
void Add(IReadOnlyList<FactorioObject> raw, DependencyList.Flags flags);
}

public struct DependencyList {
public struct DependencyList(FactorioId[] elements, DependencyList.Flags flags) {
[Flags]
public enum Flags {
RequireEverything = 0x100,
Expand All @@ -24,63 +20,43 @@ public enum Flags {
TechnologyPrerequisites = 8 | RequireEverything | OneTimeInvestment,
IngredientVariant = 9,
Hidden = 10,
Location = 11 | OneTimeInvestment,
}

public Flags flags;
public FactorioId[] elements;
public Flags flags = flags;
public FactorioId[] elements = elements;

public DependencyList(IEnumerable<FactorioObject> elements, Flags flags) : this(elements.Select(o => o.id).ToArray(), flags) { }
}

public static class Dependencies {
public static Mapping<FactorioObject, DependencyList[]> dependencyList { get; private set; }
/// <summary>
/// The objects the key requires, organized into useful categories. Some categories are requires-any, others are requires-all.
/// e.g. <c>dependencyList["Item.steel-plate"]</c> will contain the recipes that produce it and the entities that have it as loot.
/// </summary>
public static Mapping<FactorioObject, DependencyNode> dependencyList { get; private set; }
/// <summary>
/// The objects that require the key. e.g. <c>reverseDependencies["Item.steel-plate"]</c> will contain the recipes that consume steel plate.
/// </summary>
public static Mapping<FactorioObject, List<FactorioId>> reverseDependencies { get; private set; }

public static void Calculate() {
dependencyList = Database.objects.CreateMapping<DependencyList[]>();
dependencyList = Database.objects.CreateMapping<DependencyNode>();
reverseDependencies = Database.objects.CreateMapping<List<FactorioId>>();

foreach (var obj in Database.objects.all) {
reverseDependencies[obj] = [];
}

DependencyCollector collector = new DependencyCollector();
List<FactorioObject> temp = [];

foreach (var obj in Database.objects.all) {
obj.GetDependencies(collector, temp);
var packed = collector.Pack();
DependencyNode packed = obj.GetDependencies();
dependencyList[obj] = packed;

foreach (var group in packed) {
foreach (var req in group.elements) {
if (!reverseDependencies[req].Contains(obj.id)) {
reverseDependencies[req].Add(obj.id);
}
foreach (FactorioId req in packed.Flatten()) {
if (!reverseDependencies[req].Contains(obj.id)) {
reverseDependencies[req].Add(obj.id);
}
}
}
}

private class DependencyCollector : IDependencyCollector {
private readonly List<DependencyList> list = [];

public void Add(FactorioId[] raw, DependencyList.Flags flags) => list.Add(new DependencyList { elements = raw, flags = flags });

public void Add(IReadOnlyList<FactorioObject> raw, DependencyList.Flags flags) {
FactorioId[] elems = new FactorioId[raw.Count];

for (int i = 0; i < raw.Count; i++) {
elems[i] = raw[i].id;
}

list.Add(new DependencyList { elements = elems, flags = flags });
}

public DependencyList[] Pack() {
var packed = list.ToArray();
list.Clear();

return packed;
}
}

}
Loading