Fix size sorting and add regressive test
This commit is contained in:
@@ -310,7 +310,14 @@ class ModList {
|
||||
}
|
||||
|
||||
// Optimize for soft constraints
|
||||
return _optimizeSoftConstraints(loadOrder: loadOrder);
|
||||
_optimizeSoftConstraints(loadOrder: loadOrder);
|
||||
for (final modId in loadOrder.loadOrder) {
|
||||
final mod = mods[modId]!;
|
||||
print(
|
||||
'Mod ID: ${mod.id}, Name: ${mod.name}, Enabled: ${mod.enabled}, Size: ${mod.size}, Dependencies: ${mod.dependencies}, Load After: ${mod.loadAfter}, Load Before: ${mod.loadBefore}, Incompatibilities: ${mod.incompatibilities}',
|
||||
);
|
||||
}
|
||||
return loadOrder;
|
||||
}
|
||||
|
||||
/// Calculate how many soft constraints are satisfied
|
||||
@@ -356,34 +363,75 @@ class ModList {
|
||||
LoadOrder? loadOrder,
|
||||
}) {
|
||||
loadOrder ??= LoadOrder();
|
||||
Map<String, int> scoreInfo = _calculateSoftConstraintsScore(
|
||||
loadOrder.loadOrder,
|
||||
);
|
||||
|
||||
// First, ensure base game and expansions are at the beginning in the correct order
|
||||
List<String> baseAndExpansions = [];
|
||||
List<String> harmony = [];
|
||||
List<String> otherMods = [];
|
||||
|
||||
// Separate mods into categories
|
||||
for (final modId in loadOrder.loadOrder) {
|
||||
final mod = mods[modId]!;
|
||||
if (modId == 'brrainz.harmony') {
|
||||
harmony.add(modId);
|
||||
} else if (mod.isBaseGame) {
|
||||
baseAndExpansions.add(modId);
|
||||
} else if (mod.isExpansion) {
|
||||
baseAndExpansions.add(modId);
|
||||
} else {
|
||||
otherMods.add(modId);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort expansions to ensure correct order
|
||||
baseAndExpansions.sort((a, b) {
|
||||
final modA = mods[a]!;
|
||||
final modB = mods[b]!;
|
||||
|
||||
// Base game always first
|
||||
if (modA.isBaseGame) return -1;
|
||||
if (modB.isBaseGame) return 1;
|
||||
|
||||
// Sort expansions alphabetically by ID (which should work for Ludeon expansions)
|
||||
return a.compareTo(b);
|
||||
});
|
||||
|
||||
// Combine the lists with harmony first, then base game and expansions, then other mods
|
||||
loadOrder.loadOrder.clear();
|
||||
loadOrder.loadOrder.addAll(harmony);
|
||||
loadOrder.loadOrder.addAll(baseAndExpansions);
|
||||
|
||||
// Now apply the normal optimization for the remaining mods
|
||||
List<String> remainingMods = otherMods;
|
||||
|
||||
Map<String, int> scoreInfo = _calculateSoftConstraintsScore(remainingMods);
|
||||
int bestScore = scoreInfo['satisfied']!;
|
||||
int total = scoreInfo['total']!;
|
||||
|
||||
if (total == 0 || bestScore == total) {
|
||||
// All constraints satisfied or no constraints, sort by size where possible
|
||||
return _sortSizeWithinConstraints(loadOrder: loadOrder);
|
||||
// All constraints satisfied or no constraints for remaining mods, sort by size where possible
|
||||
_sortSizeWithinConstraints(loadOrder: loadOrder, modList: remainingMods);
|
||||
loadOrder.loadOrder.addAll(remainingMods);
|
||||
return loadOrder;
|
||||
}
|
||||
|
||||
// Use a limited number of improvement passes
|
||||
// Use a limited number of improvement passes for the remaining mods
|
||||
for (int iteration = 0; iteration < maxIterations; iteration++) {
|
||||
bool improved = false;
|
||||
|
||||
// Try moving each mod to improve score
|
||||
for (int i = 0; i < loadOrder.loadOrder.length; i++) {
|
||||
String modId = loadOrder.loadOrder[i];
|
||||
for (int i = 0; i < remainingMods.length; i++) {
|
||||
String modId = remainingMods[i];
|
||||
Mod mod = mods[modId]!;
|
||||
|
||||
// Calculate current local score for this mod
|
||||
Map<String, int> currentPositions = {};
|
||||
for (int idx = 0; idx < loadOrder.loadOrder.length; idx++) {
|
||||
currentPositions[loadOrder.loadOrder[idx]] = idx;
|
||||
for (int idx = 0; idx < remainingMods.length; idx++) {
|
||||
currentPositions[remainingMods[idx]] = idx;
|
||||
}
|
||||
|
||||
// Try moving this mod to different positions
|
||||
for (int newPos = 0; newPos < loadOrder.loadOrder.length; newPos++) {
|
||||
for (int newPos = 0; newPos < remainingMods.length; newPos++) {
|
||||
if (newPos == i) continue;
|
||||
|
||||
// Skip if move would break hard dependencies
|
||||
@@ -392,7 +440,7 @@ class ModList {
|
||||
// Moving earlier
|
||||
// Check if any mod between newPos and i depends on this mod
|
||||
for (int j = newPos; j < i; j++) {
|
||||
String depModId = loadOrder.loadOrder[j];
|
||||
String depModId = remainingMods[j];
|
||||
if (mods[depModId]!.dependencies.contains(modId)) {
|
||||
skip = true;
|
||||
break;
|
||||
@@ -402,7 +450,7 @@ class ModList {
|
||||
// Moving later
|
||||
// Check if this mod depends on any mod between i and newPos
|
||||
for (int j = i + 1; j <= newPos; j++) {
|
||||
String depModId = loadOrder.loadOrder[j];
|
||||
String depModId = remainingMods[j];
|
||||
if (mod.dependencies.contains(depModId)) {
|
||||
skip = true;
|
||||
break;
|
||||
@@ -413,7 +461,7 @@ class ModList {
|
||||
if (skip) continue;
|
||||
|
||||
// Create a new order with the mod moved
|
||||
List<String> newOrder = List.from(loadOrder.loadOrder);
|
||||
List<String> newOrder = List.from(remainingMods);
|
||||
newOrder.removeAt(i);
|
||||
newOrder.insert(newPos, modId);
|
||||
|
||||
@@ -425,8 +473,8 @@ class ModList {
|
||||
|
||||
if (newScore > bestScore) {
|
||||
bestScore = newScore;
|
||||
loadOrder.loadOrder.clear();
|
||||
loadOrder.loadOrder.addAll(newOrder);
|
||||
remainingMods.clear();
|
||||
remainingMods.addAll(newOrder);
|
||||
improved = true;
|
||||
break; // Break inner loop, move to next mod
|
||||
}
|
||||
@@ -438,19 +486,27 @@ class ModList {
|
||||
if (!improved) break; // If no improvements in this pass, stop
|
||||
}
|
||||
|
||||
// After optimizing for soft constraints, sort by size where possible
|
||||
return _sortSizeWithinConstraints(loadOrder: loadOrder);
|
||||
// Sort by size where possible for the remaining mods
|
||||
_sortSizeWithinConstraints(loadOrder: loadOrder, modList: remainingMods);
|
||||
loadOrder.loadOrder.addAll(remainingMods);
|
||||
|
||||
return loadOrder;
|
||||
}
|
||||
|
||||
/// Sort mods by size within compatible groups
|
||||
LoadOrder _sortSizeWithinConstraints({LoadOrder? loadOrder}) {
|
||||
LoadOrder _sortSizeWithinConstraints({
|
||||
LoadOrder? loadOrder,
|
||||
List<String>? modList,
|
||||
}) {
|
||||
loadOrder ??= LoadOrder();
|
||||
List<String> modsToSort = modList ?? loadOrder.loadOrder;
|
||||
|
||||
// Find groups of mods that can be reordered without breaking constraints
|
||||
List<List<String>> groups = [];
|
||||
List<String> currentGroup = [];
|
||||
|
||||
for (int i = 0; i < loadOrder.loadOrder.length; i++) {
|
||||
String modId = loadOrder.loadOrder[i];
|
||||
for (int i = 0; i < modsToSort.length; i++) {
|
||||
String modId = modsToSort[i];
|
||||
Mod mod = mods[modId]!;
|
||||
|
||||
if (currentGroup.isEmpty) {
|
||||
@@ -504,9 +560,15 @@ class ModList {
|
||||
}
|
||||
|
||||
// Reconstruct the order
|
||||
loadOrder.loadOrder.clear();
|
||||
modsToSort.clear();
|
||||
for (List<String> group in groups) {
|
||||
loadOrder.loadOrder.addAll(group);
|
||||
modsToSort.addAll(group);
|
||||
}
|
||||
|
||||
// If we were given the loadOrder directly, update it
|
||||
if (modList == null) {
|
||||
loadOrder.loadOrder.clear();
|
||||
loadOrder.loadOrder.addAll(modsToSort);
|
||||
}
|
||||
|
||||
return loadOrder;
|
||||
|
Reference in New Issue
Block a user