import 'dart:async'; import 'package:rimworld_modman/logger.dart'; import 'package:rimworld_modman/mod.dart'; import 'package:rimworld_modman/mod_list.dart'; /// A class that helps find the minimum set of mods that exhibit a bug. /// /// Provides two main algorithms: /// - Binary search / bisect: Divides mods into smaller subsets to find problematic ones quickly. /// - Linear search / batching: Tests mods in small groups to systematically identify issues. /// /// These approaches help RimWorld mod users identify which mods are causing problems /// when many mods are installed. class ModListTroubleshooter { final ModList originalModList; ModList currentModList; int _startIndex = 0; int _endIndex = 0; ModListTroubleshooter(ModList modList) : originalModList = modList, currentModList = modList.copyWith(), _startIndex = 0, _endIndex = modList.activeMods.length; ModList binaryForward() { final midIndex = (_startIndex + _endIndex) ~/ 2; final subset = originalModList.activeMods.keys.toList().sublist( midIndex, _endIndex, ); currentModList.disableAll(); currentModList.enableMods(subset); _startIndex = midIndex; return currentModList; } ModList binaryBackward() { final midIndex = ((_startIndex + _endIndex) / 2).ceil(); final subset = originalModList.activeMods.keys.toList().sublist( _startIndex, midIndex, ); currentModList.disableAll(); currentModList.enableMods(subset); _endIndex = midIndex; return currentModList; } ModList linearForward({int stepSize = 20}) { _endIndex = _startIndex + stepSize; final subset = originalModList.activeMods.keys.toList().sublist( _startIndex, _endIndex, ); currentModList.disableAll(); currentModList.enableMods(subset); _startIndex = _endIndex; return currentModList; } ModList linearBackward({int stepSize = 20}) { _startIndex = _endIndex - stepSize; _endIndex = _startIndex; final subset = originalModList.activeMods.keys.toList().sublist( _startIndex, _endIndex, ); currentModList.disableAll(); currentModList.enableMods(subset); _endIndex = _startIndex; return currentModList; } void reset() { currentModList = originalModList.copyWith(); } }