Skip to content

Commit

Permalink
Add CentersXY and CentersYX to eliminate arbitrary hash map ordering
Browse files Browse the repository at this point in the history
  • Loading branch information
joelverhagen committed Jan 10, 2024
1 parent 99391d5 commit b4b117b
Show file tree
Hide file tree
Showing 859 changed files with 13,345 additions and 13,301 deletions.
2 changes: 1 addition & 1 deletion src/FactorioTools/OilField/Containers/EmptyLocationSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void CopyTo(Location[] array)
{
}

public IEnumerable<Location> EnumerateItems()
public IReadOnlyCollection<Location> EnumerateItems()
{
return Array.Empty<Location>();
}
Expand Down
2 changes: 1 addition & 1 deletion src/FactorioTools/OilField/Containers/ILocationSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface ILocationSet
void Clear();
bool Contains(Location location);
void CopyTo(Location[] array);
IEnumerable<Location> EnumerateItems();
IReadOnlyCollection<Location> EnumerateItems();
void ExceptWith(ILocationSet other);
bool Overlaps(IEnumerable<Location> other);
bool Remove(Location location);
Expand Down
2 changes: 1 addition & 1 deletion src/FactorioTools/OilField/Containers/LocationBitSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public void CopyTo(Location[] array)
throw new NotSupportedException();
}

public IEnumerable<Location> EnumerateItems()
public IReadOnlyCollection<Location> EnumerateItems()
{
throw new NotSupportedException();
}
Expand Down
2 changes: 1 addition & 1 deletion src/FactorioTools/OilField/Containers/LocationHashSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void CopyTo(Location[] array)
_set.CopyTo(array);
}

public IEnumerable<Location> EnumerateItems()
public IReadOnlyCollection<Location> EnumerateItems()
{
return _set;
}
Expand Down
2 changes: 1 addition & 1 deletion src/FactorioTools/OilField/Containers/LocationIntSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public void CopyTo(Location[] array)
}
}

public IEnumerable<Location> EnumerateItems()
public IReadOnlyCollection<Location> EnumerateItems()
{
var items = new List<Location>(_set.Count);
foreach (var item in _set)
Expand Down
2 changes: 1 addition & 1 deletion src/FactorioTools/OilField/Containers/SingleLocationSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void CopyTo(Location[] array)
array[0] = new Location(_x, _y);
}

public IEnumerable<Location> EnumerateItems()
public IReadOnlyCollection<Location> EnumerateItems()
{
return _hasItem ? new[] { new Location(_x, _y) } : Array.Empty<Location>();
}
Expand Down
36 changes: 28 additions & 8 deletions src/FactorioTools/OilField/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ public static void AddPath(ILocationDictionary<Location> cameFrom, Location reac
}
}

public static bool AreLocationsCollinear(List<Location> locations)
public static bool AreLocationsCollinear(IReadOnlyList<Location> locations)
{
double lastSlope = 0;
for (var i = 0; i < locations.Count; i++)
Expand Down Expand Up @@ -1080,16 +1080,36 @@ public static List<Location> MakeStraightLine(Location a, Location b)
throw new ArgumentException("The two points must be one the same line either horizontally or vertically.");
}

public static List<Endpoints> PointsToLines(IReadOnlyCollection<Location> nodes)
{
return PointsToLines(nodes.ToList(), sort: true);
}

/// <summary>
/// Source: https://github.com/teoxoy/factorio-blueprint-editor/blob/21ab873d8316a41b9a05c719697d461d3ede095d/packages/editor/src/core/generators/util.ts#L62
/// </summary>
public static List<Endpoints> PointsToLines(Context context, IReadOnlyCollection<Location> nodes)
public static List<Endpoints> PointsToLines(IReadOnlyList<Location> nodes, bool sort)
{
var filteredNodes = nodes
.Distinct(context)
.OrderBy(x => x.X)
.ThenBy(x => x.Y)
.ToList();
IReadOnlyList<Location> filteredNodes;
if (sort)
{
var sortedXY = nodes.ToList();
sortedXY.Sort((a, b) =>
{
var c = a.X.CompareTo(b.X);
if (c != 0)
{
return c;
}

return a.Y.CompareTo(b.Y);
});
filteredNodes = sortedXY;
}
else
{
filteredNodes = nodes;
}

if (filteredNodes.Count == 1)
{
Expand All @@ -1104,7 +1124,7 @@ public static List<Endpoints> PointsToLines(Context context, IReadOnlyCollection
if (AreLocationsCollinear(filteredNodes))
{
return Enumerable
.Range(1, filteredNodes.Count - 1)
.Range(1, filteredNodes.Count - 1)
.Select(i => new Endpoints(filteredNodes[i - 1], filteredNodes[i]))
.ToList();
}
Expand Down
2 changes: 2 additions & 0 deletions src/FactorioTools/OilField/Models/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public class Context
public required OilFieldOptions Options { get; set; }
public required Blueprint InputBlueprint { get; set; }
public required SquareGrid Grid { get; set; }
public required List<Location> CentersXY { get; set; }
public required List<Location> CentersYX { get; set; }
public required ILocationDictionary<List<TerminalLocation>> CenterToTerminals { get; set; }
public required ILocationDictionary<Direction> CenterToOriginalDirection { get; set; }
public required ILocationDictionary<List<TerminalLocation>> LocationToTerminals { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion src/FactorioTools/OilField/Steps/AddElectricPoles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ private static void ConnectElectricPoles(Context context, ILocationDictionary<El

while (groups.Count > 1)
{
var closest = PointsToLines(context, electricPoles.Keys)
var closest = PointsToLines(electricPoles.Keys)
.Select(e => new
{
Endpoints = e,
Expand Down
22 changes: 16 additions & 6 deletions src/FactorioTools/OilField/Steps/AddPipes.1.FBE.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static (ILocationSet Pipes, PipeStrategy FinalStrategy) ExecuteWithFbe(Co
private static (List<TerminalLocation> Terminals, ILocationSet Pipes, PipeStrategy FinalStrategy) DelaunayTriangulation(Context context, Location middle, PipeStrategy strategy)
{
// GENERATE LINES
var lines = PointsToLines(context, context.CenterToTerminals.Keys)
var lines = PointsToLines(context.CentersXY, sort: false)
.Select(line =>
{
var connections = context.CenterToTerminals[line.A]
Expand Down Expand Up @@ -107,7 +107,7 @@ private static (List<TerminalLocation> Terminals, ILocationSet Pipes, PipeStrate
// this will only happen when only a few pumpjacks need to be connected
if (groups.Count == 0)
{
var connection = PointsToLines(context, context.CenterToTerminals.Keys)
var connection = PointsToLines(context.CentersXY, sort: false)
.Select(line =>
{
return context.CenterToTerminals[line.A]
Expand Down Expand Up @@ -156,7 +156,7 @@ private static (List<TerminalLocation> Terminals, ILocationSet Pipes, PipeStrate
var locationToGroup = groups.ToDictionary(context, x => x.Location, x => x);
locationToGroup.Add(group.Location, group);

var par = PointsToLines(context, locationToGroup.Keys)
var par = PointsToLines(locationToGroup.Keys)
.Where(l => l.A == group.Location || l.B == group.Location)
.Select(l => l.A == group.Location ? l.B : l.A)
.Select(l => locationToGroup[l])
Expand Down Expand Up @@ -201,8 +201,7 @@ private static (List<TerminalLocation> Terminals, ILocationSet Pipes, PipeStrate
}

var leftoverPumpjacks = context
.CenterToTerminals
.Keys
.CentersXY
.Except(addedPumpjacks.Select(x => x.Center), context)
.OrderBy(l => l.GetManhattanDistance(true ? middle : context.Grid.Middle));

Expand Down Expand Up @@ -300,7 +299,18 @@ private static TwoConnectedGroups ConnectTwoGroups(Context context, Group a, Gro
bLocationsOptimized = bLocations;
}

lines.AddRange(PointsToLines(context, aLocations.Concat(bLocationsOptimized).ToList())
var aPlusB = context.GetLocationSet(aLocations.Count + bLocationsOptimized.Count, allowEnumerate: true);
for (var i = 0; i < aLocations.Count; i++)
{
aPlusB.Add(aLocations[i]);
}

for (var i = 0; i < bLocationsOptimized.Count; i++)
{
aPlusB.Add(bLocationsOptimized[i]);
}

lines.AddRange(PointsToLines(aPlusB.EnumerateItems())
.Where(p => !((aLocations.Contains(p.A) && aLocations.Contains(p.B)) || (bLocations.Contains(p.A) && bLocations.Contains(p.B))))
.OrderBy(p => p.A.GetManhattanDistance(p.B))
.Take(5)
Expand Down
24 changes: 6 additions & 18 deletions src/FactorioTools/OilField/Steps/AddPipes.2.ConnectedCenters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,7 @@ public static partial class AddPipes

private static ILocationDictionary<ILocationSet> GetConnectedPumpjacks(Context context, PipeStrategy strategy)
{
var centers = context.CenterToTerminals.Keys.ToList();
centers.Sort((a, b) =>
{
var c = a.X.CompareTo(b.X);
if (c != 0)
{
return c;
}

return a.Y.CompareTo(b.Y);
});
var centers = context.CentersXY;

if (centers.Count == 2)
{
Expand Down Expand Up @@ -416,8 +406,8 @@ private static List<Trunk> FindTrunks(Context context, ILocationDictionary<ILoca

private static PumpjackGroup ConnectTwoClosestPumpjacks(Context context, ILocationDictionary<ILocationSet> centerToConnectedCenters, ILocationSet allIncludedCenters)
{
var bestConnection = centerToConnectedCenters
.Keys
var bestConnection = context
.CentersYX
.Select(center =>
{
return context
Expand Down Expand Up @@ -505,19 +495,17 @@ private static ILocationSet GetChildCenters(
private static List<Trunk> GetTrunkCandidates(Context context, ILocationDictionary<ILocationSet> centerToConnectedCenters)
{
var centerToMaxX = context
.CenterToTerminals
.Keys
.CentersXY
.ToDictionary(context, c => c, c => centerToConnectedCenters[c].EnumerateItems().Max(c => context.CenterToTerminals[c].Max(t => t.Terminal.X)));
var centerToMaxY = context
.CenterToTerminals
.Keys
.CentersXY
.ToDictionary(context, c => c, c => centerToConnectedCenters[c].EnumerateItems().Max(c => context.CenterToTerminals[c].Max(t => t.Terminal.Y)));

// Find paths that connect the most terminals of neighboring pumpjacks.
var trunkCandidates = new List<Trunk>();
foreach (var translation in Translations)
{
foreach (var startingCenter in context.CenterToTerminals.Keys.OrderBy(c => c.Y).ThenBy(c => c.X))
foreach (var startingCenter in context.CentersYX)
{
foreach (var terminal in context.CenterToTerminals[startingCenter])
{
Expand Down
15 changes: 1 addition & 14 deletions src/FactorioTools/OilField/Steps/CleanBlueprint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,7 @@ public static Blueprint Execute(Blueprint blueprint)

var entities = new List<Entity>();

// Pumpjacks are sorted by their Y coordinate, then their X coordinate.
var sortedCenters = context.CenterToTerminals.Keys.ToList();
sortedCenters.Sort((a, b) =>
{
var c = a.Y.CompareTo(b.Y);
if (c != 0)
{
return c;
}

return a.X.CompareTo(b.X);
});

foreach (var center in sortedCenters)
foreach (var center in context.CentersYX)
{
// Pumpjacks are given a direction that doesn't overlap with another pumpjack, preferring the direction
// starting at the top then proceeding clockwise.
Expand Down
51 changes: 44 additions & 7 deletions src/FactorioTools/OilField/Steps/InitializeContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,53 @@ private static Context Execute(OilFieldOptions options, Blueprint blueprint, int

var grid = InitializeGrid(centerAndOriginalDirections, marginX, marginY);

var centersXY = new List<Location>(centerAndOriginalDirections.Count);
PopulateCenters(centerAndOriginalDirections, centersXY);
centersXY.Sort((a, b) =>
{
var c = a.X.CompareTo(b.X);
if (c != 0)
{
return c;
}

return a.Y.CompareTo(b.Y);
});

var centersYX = new List<Location>(centerAndOriginalDirections.Count);
PopulateCenters(centerAndOriginalDirections, centersYX);
centersYX.Sort((a, b) =>
{
var c = a.Y.CompareTo(b.Y);
if (c != 0)
{
return c;
}

return a.X.CompareTo(b.X);
});

#if USE_HASHSETS
var centerToOriginalDirection = new LocationHashDictionary<Direction>();
var centerToTerminals = new LocationHashDictionary<List<TerminalLocation>>();
var centerToOriginalDirection = new LocationHashDictionary<Direction>(centerAndOriginalDirections.Count);
var centerToTerminals = new LocationHashDictionary<List<TerminalLocation>>(centerAndOriginalDirections.Count);
var locationToTerminals = new LocationHashDictionary<List<TerminalLocation>>();
#else
var centerToOriginalDirection = new LocationIntDictionary<Direction>(grid.Width);
var centerToTerminals = new LocationIntDictionary<List<TerminalLocation>>(grid.Width);
var centerToOriginalDirection = new LocationIntDictionary<Direction>(grid.Width, centerAndOriginalDirections.Count);
var centerToTerminals = new LocationIntDictionary<List<TerminalLocation>>(grid.Width, centerAndOriginalDirections.Count);
var locationToTerminals = new LocationIntDictionary<List<TerminalLocation>>(grid.Width);
#endif

PopulateCenterToOriginalDirection(centerAndOriginalDirections, centerToOriginalDirection);
PopulateCenterToTerminals(centerToTerminals, grid, centerToOriginalDirection.Keys);
PopulateCenterToTerminals(centerToTerminals, grid, centersXY);
PopulateLocationToTerminals(locationToTerminals, centerToTerminals);

return new Context
{
Options = options,
InputBlueprint = blueprint,
Grid = grid,
CentersXY = centersXY,
CentersYX = centersYX,
CenterToTerminals = centerToTerminals,
CenterToOriginalDirection = centerToOriginalDirection,
LocationToTerminals = locationToTerminals,
Expand All @@ -82,11 +110,20 @@ private static Context Execute(OilFieldOptions options, Blueprint blueprint, int
};
}

private static void PopulateCenters(List<Tuple<Location, Direction>> centerAndOriginalDirections, List<Location> centers)
{
for (int i = 0; i < centerAndOriginalDirections.Count; i++)
{
centers.Add(centerAndOriginalDirections[i].Item1);
}
}

private static void PopulateCenterToOriginalDirection(List<Tuple<Location, Direction>> centerAndOriginalDirections, ILocationDictionary<Direction> centerToOriginalDirection)
{
foreach ((var center, var originalDirection) in centerAndOriginalDirections)
for (int i = 0; i < centerAndOriginalDirections.Count; i++)
{
centerToOriginalDirection.Add(center, originalDirection);
var pair = centerAndOriginalDirections[i];
centerToOriginalDirection.Add(pair.Item1, pair.Item2);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/FactorioTools/OilField/Steps/PlanBeacons.1.FBE.cs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ private static List<Location[]> GetPossibleBeaconAreas(Context context, ILocatio

var area = new Location[context.Options.BeaconWidth * context.Options.BeaconHeight];

foreach (var center in context.CenterToTerminals.Keys)
foreach (var center in context.CentersXY)
{
var supplyMinX = Math.Max(gridMinX, center.X - supplyLeft);
var supplyMinY = Math.Max(gridMinY, center.Y - supplyUp);
Expand Down
2 changes: 1 addition & 1 deletion src/FactorioTools/OilField/Steps/PlanBeacons.2.Snug.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public static partial class PlanBeacons
private static (List<Location> Beacons, int Effects) AddBeaconsSnug(Context context)
{
var poweredEntities = new List<ProviderRecipient>(context.CenterToTerminals.Count);
foreach (var center in context.CenterToTerminals.Keys)
foreach (var center in context.CentersXY)
{
poweredEntities.Add(new ProviderRecipient(center, PumpjackWidth, PumpjackHeight));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ S FBE* -> FBE* (effects: 169, beacons: 127, pipes: 64)
CC-DT-MST -> FBE (effects: 158, beacons: 120, pipes: 69)
CC-DT-MST -> FBE* (effects: 156, beacons: 118, pipes: 69)
CC-DT-MST -> snug (effects: 154, beacons: 120, pipes: 69)
CC-DT-MST -> optimize -> FBE (effects: 161, beacons: 121, pipes: 72)
CC-DT-MST -> optimize -> FBE* (effects: 160, beacons: 120, pipes: 72)
CC-DT-MST -> optimize -> snug (effects: 155, beacons: 118, pipes: 72)
CC-DT-MST -> optimize -> FBE (effects: 163, beacons: 122, pipes: 65)
CC-DT-MST -> optimize -> FBE* (effects: 163, beacons: 122, pipes: 65)
CC-DT-MST -> optimize -> snug (effects: 159, beacons: 120, pipes: 65)
CC-FLUTE -> FBE (effects: 161, beacons: 121, pipes: 69)
CC-FLUTE -> FBE* (effects: 161, beacons: 121, pipes: 69)
CC-FLUTE -> snug (effects: 158, beacons: 120, pipes: 69)
Expand Down
Loading

0 comments on commit b4b117b

Please sign in to comment.