Last active
September 4, 2025 21:24
-
-
Save ImaginaryDevelopment/5c8646d229c3acd0ab968349f2c18d1c to your computer and use it in GitHub Desktop.
Revisions
-
ImaginaryDevelopment revised this gist
Sep 4, 2025 . 1 changed file with 5 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -345,7 +345,7 @@ module TestData = newTestCase :: testCases // Current formula version - increment this when formulas change let currentFormulaVersion = "v1.2.0" // Function to update formula version (call this when you change formulas) let updateFormulaVersion (newVersion: string) = @@ -1173,12 +1173,12 @@ module Formulas = decimal (level * level) * 0.0215m let calculateBaseShipSpeed (level: int) : decimal = // Official formula: 1 + 0.2 * (level - 1) + (1/75) * (level - 1)² 1.0m + 0.2m * decimal (level - 1) + (1.0m / 75.0m) * decimal ((level - 1) * (level - 1)) let calculateBaseCargoSpace (level: int) : int = // Official formula: 5 + 2 * (level - 1) + 0.1 * (level - 1)² int (5.0m + 2.0m * decimal (level - 1) + 0.1m * decimal ((level - 1) * (level - 1))) // Alternative formulas for testing let calculateBaseMiningRateV2 (level: int) : decimal = -
ImaginaryDevelopment created this gist
Sep 4, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,1719 @@ module IdlePlanetMiner // ============================================================================= // CORE DATA TYPES // ============================================================================= // Planet information from the wiki type Planet = { Name: string BasePrice: int Distance: int Tele: int option Resources: Map<string, decimal> } // Planet level information type PlanetLevels = { Mining: int ShipSpeed: int Cargo: int } // Planet stats (calculated results) type PlanetStats = { OrePerSecond: decimal Speed: decimal Cargo: int } // Modifier source for debugging type ModifierSource = { Name: string Value: decimal Description: string } // Planet calculation result with modifiers type PlanetCalculationResult = { FinalStats: PlanetStats MiningModifiers: ModifierSource list SpeedModifiers: ModifierSource list CargoModifiers: ModifierSource list } // Planet multiplier for beacons type PlanetMultiplier = { Mining: decimal Speed: decimal Cargo: decimal } // Research information type Research = { Name: string Description: string Multipliers: Map<string, decimal> // Stat name -> multiplier (e.g., "Mining" -> 1.25m, "Speed" -> 1.15m) Cost: int } // Beacon information type Beacon = { Name: string PlanetRange: int * int // (start, end) inclusive Multipliers: PlanetMultiplier } // User multipliers and settings type Multipliers = { MiningRate: decimal ShipSpeed: decimal Cargo: decimal ColonizationBonuses: Map<int, PlanetMultiplier> Daughtership: bool RoomLevels: Map<string, int> // Room name -> level CompletedResearches: string list // List of completed research names GlobalManagerBonuses: Map<string, string * decimal> // Manager name -> (bonus type, value) } // Room information type Room = { Name: string Boost: string MinCost: int BaseEffect: decimal PerLevel: decimal MaxLevel: int MaxBonus: decimal } // Test data types type PlanetTestData = { PlanetNumber: int InputLevels: PlanetLevels ActualResults: PlanetStats } type TestCase = { TestDate: string Description: string PlanetData: PlanetTestData list CapturedMultipliers: Multipliers CapturedPurchasedBonuses: {| MineBoost: decimal |} CapturedDaughtershipMultipliers: {| MiningRate: decimal; ShipSpeed: decimal; Cargo: decimal |} CapturedBeacons: Map<string, Beacon> LastCalculatedAccuracy: decimal option FormulaVersion: string option } // Validation result types type PlanetValidationResult = { PlanetNumber: int CalculatedStats: PlanetStats ActualStats: PlanetStats MiningAccuracy: decimal SpeedAccuracy: decimal CargoAccuracy: decimal OverallAccuracy: decimal } type TestCaseValidationResult = { TestCaseDescription: string TestDate: string PlanetResults: PlanetValidationResult list AverageAccuracy: decimal } type AccuracyComparison = { TestCaseDescription: string PreviousAccuracy: decimal option CurrentAccuracy: decimal AccuracyChange: decimal option FormulaVersion: string option } // ============================================================================= // TEST DATA MODULE - Input levels and actual results for validation // ============================================================================= module TestData = // Test cases with multiple planets, actual results, and captured multipliers let testCases = [ { TestDate = "2025-09-04" Description = "Initial test case - Planets 1-13 data recorded before Advanced Mining research" PlanetData = [ { PlanetNumber = 1 InputLevels = { Mining = 34; ShipSpeed = 16; Cargo = 16 } ActualResults = { OrePerSecond = 76.62m; Speed = 15.93m; Cargo = 75 } } { PlanetNumber = 2 InputLevels = { Mining = 25; ShipSpeed = 14; Cargo = 14 } ActualResults = { OrePerSecond = 43.21m; Speed = 13.32m; Cargo = 62 } } { PlanetNumber = 3 InputLevels = { Mining = 21; ShipSpeed = 11; Cargo = 11 } ActualResults = { OrePerSecond = 24.17m; Speed = 9.86m; Cargo = 45 } } ] CapturedMultipliers = { MiningRate = 1.0m ShipSpeed = 1.0m Cargo = 1.0m ColonizationBonuses = Map [ 1, { Mining = 1.3m; Speed = 1.0m; Cargo = 1.0m } // Planet 1 colonized 2, { Mining = 1.3m; Speed = 1.0m; Cargo = 1.0m } // Planet 2 colonized ] Daughtership = true RoomLevels = Map [ "Engineering", 1 // Level 1 Engineering room "Aeronautical", 2 // Level 2 Aeronautical room "Packaging", 0 // No Packaging room yet ] CompletedResearches = [] // No research completed when data was recorded GlobalManagerBonuses = Map [] // No global manager bonuses when data was recorded } CapturedPurchasedBonuses = { MineBoost = 1.2m } CapturedDaughtershipMultipliers = { MiningRate = 1.5m ShipSpeed = 1.25m Cargo = 1.25m } CapturedBeacons = Map [ "Beacon 1-4", { Name = "Beacon 1-4" PlanetRange = (1, 4) Multipliers = { Mining = 1.06m Speed = 1.04m Cargo = 1.04m } } "Beacon 5-7", { Name = "Beacon 5-7" PlanetRange = (5, 7) Multipliers = { Mining = 1.06m Speed = 1.04m Cargo = 1.04m } } "Beacon 8-10", { Name = "Beacon 8-10" PlanetRange = (8, 10) Multipliers = { Mining = 1.06m Speed = 1.0m Cargo = 1.04m } } "Beacon 11-13", { Name = "Beacon 11-13" PlanetRange = (11, 13) Multipliers = { Mining = 1.06m Speed = 1.0m Cargo = 1.04m } } "Beacon 14-16", { Name = "Beacon 14-16" PlanetRange = (14, 16) Multipliers = { Mining = 1.06m Speed = 1.0m Cargo = 1.04m } } ] LastCalculatedAccuracy = None // Will be calculated during validation FormulaVersion = None // Will be set during validation } { TestDate = "2025-01-27" Description = "Current test case - Planets 1-13 with updated levels and current bonuses" PlanetData = [ { PlanetNumber = 1 InputLevels = { Mining = 34; ShipSpeed = 20; Cargo = 20 } ActualResults = { OrePerSecond = 95.77m; Speed = 24.06m; Cargo = 103 } } { PlanetNumber = 2 InputLevels = { Mining = 25; ShipSpeed = 15; Cargo = 15 } ActualResults = { OrePerSecond = 54.01m; Speed = 16.05m; Cargo = 68 } } { PlanetNumber = 3 InputLevels = { Mining = 23; ShipSpeed = 13; Cargo = 13 } ActualResults = { OrePerSecond = 35.65m; Speed = 13.31m; Cargo = 56 } } { PlanetNumber = 4 InputLevels = { Mining = 20; ShipSpeed = 10; Cargo = 10 } ActualResults = { OrePerSecond = 27.67m; Speed = 9.71m; Cargo = 40 } } { PlanetNumber = 5 InputLevels = { Mining = 13; ShipSpeed = 7; Cargo = 9 } ActualResults = { OrePerSecond = 13.02m; Speed = 6.71m; Cargo = 36 } } { PlanetNumber = 6 InputLevels = { Mining = 16; ShipSpeed = 11; Cargo = 11 } ActualResults = { OrePerSecond = 18.61m; Speed = 10.84m; Cargo = 45 } } { PlanetNumber = 7 InputLevels = { Mining = 14; ShipSpeed = 8; Cargo = 8 } ActualResults = { OrePerSecond = 14.77m; Speed = 7.64m; Cargo = 31 } } { PlanetNumber = 8 InputLevels = { Mining = 15; ShipSpeed = 10; Cargo = 10 } ActualResults = { OrePerSecond = 16.63m; Speed = 9.71m; Cargo = 40 } } { PlanetNumber = 9 InputLevels = { Mining = 12; ShipSpeed = 8; Cargo = 8 } ActualResults = { OrePerSecond = 11.38m; Speed = 7.64m; Cargo = 31 } } { PlanetNumber = 10 InputLevels = { Mining = 12; ShipSpeed = 7; Cargo = 7 } ActualResults = { OrePerSecond = 11.38m; Speed = 6.71m; Cargo = 27 } } { PlanetNumber = 11 InputLevels = { Mining = 12; ShipSpeed = 5; Cargo = 6 } ActualResults = { OrePerSecond = 11.38m; Speed = 9.69m; Cargo = 23 } } { PlanetNumber = 12 InputLevels = { Mining = 12; ShipSpeed = 7; Cargo = 7 } ActualResults = { OrePerSecond = 11.38m; Speed = 6.45m; Cargo = 27 } } { PlanetNumber = 13 InputLevels = { Mining = 13; ShipSpeed = 7; Cargo = 7 } ActualResults = { OrePerSecond = 13.02m; Speed = 6.45m; Cargo = 27 } } ] CapturedMultipliers = UserInput.multipliers CapturedPurchasedBonuses = UserInput.purchasedBonuses CapturedDaughtershipMultipliers = UserInput.daughtershipMultipliers CapturedBeacons = UserInput.beacons LastCalculatedAccuracy = None // Will be calculated during validation FormulaVersion = None // Will be set during validation } ] // Function to capture current state as a new test case with multiple planets let captureCurrentState (planetData: PlanetTestData list) (description: string) : TestCase = { TestDate = System.DateTime.Now.ToString("yyyy-MM-dd") Description = description PlanetData = planetData CapturedMultipliers = UserInput.multipliers CapturedPurchasedBonuses = UserInput.purchasedBonuses CapturedDaughtershipMultipliers = UserInput.daughtershipMultipliers CapturedBeacons = UserInput.beacons LastCalculatedAccuracy = None // Will be calculated during validation FormulaVersion = None // Will be set during validation } // Helper function to create a single planet test data let createPlanetTestData (planetNumber: int) (inputLevels: PlanetLevels) (actualResults: PlanetStats) : PlanetTestData = { PlanetNumber = planetNumber InputLevels = inputLevels ActualResults = actualResults } // Helper function to add a new test case to the list let addTestCase (newTestCase: TestCase) : TestCase list = newTestCase :: testCases // Current formula version - increment this when formulas change let currentFormulaVersion = "v1.1.0" // Function to update formula version (call this when you change formulas) let updateFormulaVersion (newVersion: string) = printfn "Formula version updated to: %s" newVersion printfn "Previous version was: %s" currentFormulaVersion printfn "Run validation to see accuracy changes!" // ============================================================================= // USER INPUT MODULE - Current user game settings // ============================================================================= module UserInput = // Your current game multipliers and settings let multipliers = { MiningRate = 1.0m // Base mining rate multiplier ShipSpeed = 1.0m Cargo = 1.0m ColonizationBonuses = Map [ 1, { Mining = 1.3m; Speed = 1.0m; Cargo = 1.0m } // Planet 1 colonized 2, { Mining = 1.3m; Speed = 1.0m; Cargo = 1.0m } // Planet 2 colonized ] Daughtership = true // You have daughtership RoomLevels = Map [ "Engineering", 1 // Level 1 Engineering room "Aeronautical", 2 // Level 2 Aeronautical room "Packaging", 0 // No Packaging room yet ] CompletedResearches = [ "Advanced Mining" // You have completed this research // "Advanced Furnace" // You have completed this research // Add more completed researches here ] GlobalManagerBonuses = Map [ // Example: "Mining Manager", ("Mining", 1.15m) // 15% mining bonus // Example: "Speed Manager", ("Speed", 1.10m) // 10% speed bonus // Example: "Cargo Manager", ("Cargo", 1.20m) // 20% cargo bonus "Dominique", ("Speed", 1.10m) ] } let purchasedBonuses = { MineBoost = 1.2m // Purchased mine boost (separate from base rate) } let daughtershipMultipliers = { MiningRate = 1.5m ShipSpeed = 1.25m Cargo = 1.25m } let beacons = Map [ "Beacon 1-4", { Name = "Beacon 1-4" PlanetRange = (1, 4) Multipliers = { Mining = 1.06m // Your current mining bonus for planets 1-4 Speed = 1.04m // Your current speed bonus for planets 1-4 Cargo = 1.04m // Your current cargo bonus for planets 1-4 } } "Beacon 5-7", { Name = "Beacon 5-7" PlanetRange = (5, 7) Multipliers = { Mining = 1.06m // Your current mining bonus for planets 5-7 Speed = 1.04m // Your current speed bonus for planets 5-7 Cargo = 1.04m // Your current cargo bonus for planets 5-7 } } "Beacon 8-10", { Name = "Beacon 8-10" PlanetRange = (8, 10) Multipliers = { Mining = 1.06m // Your current mining bonus for planets 8-10 Speed = 1.04m // Your current speed bonus for planets 8-10 (no bonus) Cargo = 1.04m // Your current cargo bonus for planets 8-10 } } "Beacon 11-13", { Name = "Beacon 11-13" PlanetRange = (11, 13) Multipliers = { Mining = 1.06m // Your current mining bonus for planets 11-13 Speed = 1.0m // Your current speed bonus for planets 11-13 (no bonus) Cargo = 1.04m // Your current cargo bonus for planets 11-13 } } "Beacon 14-16", { Name = "Beacon 14-16" PlanetRange = (14, 16) Multipliers = { Mining = 1.06m // Your current mining bonus for planets 14-16 Speed = 1.0m // Your current speed bonus for planets 14-16 (no bonus) Cargo = 1.04m // Your current cargo bonus for planets 14-16 } } ] // ============================================================================= // CORE DATA TYPES // ============================================================================= // idle planet miner type Planet = { Name: string BasePrice: int Tele: int option Distance: int Resources: Map<string, decimal> } type PlanetLevels = { Mining: int ShipSpeed: int Cargo: int } type PlanetStats = { OrePerSecond: decimal Speed: decimal Cargo: int } type ModifierSource = { Name: string Value: decimal Description: string } type PlanetCalculationResult = { FinalStats: PlanetStats MiningModifiers: ModifierSource list SpeedModifiers: ModifierSource list CargoModifiers: ModifierSource list } type PlanetMultiplier = { Mining: decimal Speed: decimal Cargo: decimal } type Research = { Name: string Description: string Multipliers: Map<string, decimal> // Stat name -> multiplier (e.g., "Mining" -> 1.25m, "Speed" -> 1.15m) Cost: int } type Beacon = { Name: string PlanetRange: int * int // (start, end) inclusive Multipliers: PlanetMultiplier } type Room = { Name: string Boost: string MinCost: int BaseEffect: decimal PerLevel: decimal MaxLevel: int MaxBonus: decimal } let planets = Map[1, // https://idle-planet-miner.fandom.com/wiki/Planets { Name = "Balor" BasePrice = 100 Distance = 10 Tele = None Resources = Map["Copper", 1.0m] } 2, { Name = "Drasta" BasePrice = 200 Distance = 12 Tele = None Resources = Map [ "Copper", 0.8m; "Iron", 0.2m ] } 3, { Name = "Anadius" BasePrice = 500 Distance = 14 Tele = None Resources = Map [ "Copper", 0.5m; "Iron", 0.5m ] } 4, { Name = "Dholen" BasePrice = 1_250 Distance = 15 Tele = None Resources = Map [ "Iron", 0.8m; "Lead", 0.2m ] } 5, { Name = "Verr" BasePrice = 5_000 Distance = 16 Tele = Some 1 Resources = Map [ "Lead", 0.5m; "Iron", 0.3m; "Copper", 0.2m ] } 6, { Name = "Newton" BasePrice = 9_000 Distance = 18 Tele = Some 1 Resources = Map["Lead", 1.0m] } 7, { Name = "Widow" BasePrice = 15_000 Distance = 20 Tele = Some 1 Resources = Map [ "Iron", 0.4m; "Copper", 0.4m; "Silica", 0.2m ] } 8, { Name = "Acheron" BasePrice = 25_000 Distance = 22 Tele = Some 2 Resources = Map [ "Silica", 0.6m; "Copper", 0.4m ] } 9, { Name = "Yangtze" BasePrice = 40_000 Distance = 23 Tele = Some 2 Resources = Map [ "Silica", 0.8m; "Aluminium", 0.2m ] } 10, { Name = "Solveig" BasePrice = 75_000 Distance = 25 Tele = Some 2 Resources = Map [ "Aluminium", 0.5m; "Silica", 0.3m; "Lead", 0.2m ] } 11, { Name = "Imir" BasePrice = 150_000 Distance = 26 Tele = Some 3 Resources = Map [ "Aluminium", 1.0m ] } 12, { Name = "Relic" BasePrice = 250_000 Distance = 28 Tele = Some 3 Resources = Map [ "Lead", 0.45m; "Silica", 0.35m; "Silver", 0.2m ] } 13, { Name = "Nith" BasePrice = 400_000 Distance = 30 Tele = Some 3 Resources = Map [ "Silver", 0.8m; "Aluminium", 0.2m ] } 14, { Name = "Batalla" BasePrice = 800_000 Distance = 33 Tele = Some 4 Resources = Map [ "Copper", 0.4m; "Iron", 0.4m; "Gold", 0.2m ] } 15, { Name = "Micah" BasePrice = 1_500_000 Distance = 35 Tele = Some 4 Resources = Map [ "Gold", 0.5m; "Silver", 0.5m ] } 16, { Name = "Pranas" BasePrice = 3_000_000 Distance = 37 Tele = Some 4 Resources = Map [ "Gold", 1.0m ] } 17, { Name = "Castellus" BasePrice = 6_000_000 Distance = 40 Tele = Some 5 Resources = Map [ "Aluminium", 0.4m; "Silica", 0.35m; "Diamond", 0.25m ] }] let levels = Map[ // Planet, (Levels, Stats) 1, ({ Mining = 34 ShipSpeed = 20 Cargo = 20 }, { OrePerSecond = 95.77m Speed = 24.06m Cargo = 103 }) 2, ({ Mining = 25 ShipSpeed = 15 Cargo = 15 }, { OrePerSecond = 54.01m Speed = 16.05m Cargo = 68 }) 3, ({ Mining = 23 ShipSpeed = 13 Cargo = 13 }, { OrePerSecond = 35.65m Speed = 13.31m Cargo = 56 }) 4, ({ Mining = 20 ShipSpeed = 10 Cargo = 10 }, { OrePerSecond = 27.67m Speed = 9.71m Cargo = 40 }) 5, ({ Mining = 13 ShipSpeed = 7 Cargo = 9 }, { OrePerSecond = 13.02m Speed = 6.71m Cargo = 36 }) 6, ({ Mining = 16 ShipSpeed = 11 Cargo = 11 }, { OrePerSecond = 18.61m Speed = 10.84m Cargo = 45 }) 7, ({ Mining = 14 ShipSpeed = 8 Cargo = 8 }, { OrePerSecond = 14.77m Speed = 7.64m Cargo = 31 }) 8, ({ Mining = 15 ShipSpeed = 10 Cargo = 10 }, { OrePerSecond = 16.63m Speed = 9.71m Cargo = 40 }) 9, ({ Mining = 12 ShipSpeed = 8 Cargo = 8 }, { OrePerSecond = 11.38m Speed = 7.64m Cargo = 31 }) 10, ({ Mining = 12 ShipSpeed = 7 Cargo = 7 }, { OrePerSecond = 11.38m Speed = 6.71m Cargo = 27 }) 11, ({ Mining = 12 ShipSpeed = 5 Cargo = 6 }, { OrePerSecond = 11.38m Speed = 9.69m Cargo = 23 }) 12, ({ Mining = 12 ShipSpeed = 7 Cargo = 7 }, { OrePerSecond = 11.38m Speed = 6.45m Cargo = 27 }) 13, ({ Mining = 13 ShipSpeed = 7 Cargo = 7 }, { OrePerSecond = 13.02m Speed = 6.45m Cargo = 27 }) ] let rooms = Map [ // From wiki: https://idle-planet-miner.fandom.com/wiki/Rooms "Engineering", { Name = "Engineering" Boost = "Increase mine speed" MinCost = 3 BaseEffect = 1.25m PerLevel = 0.15m MaxLevel = 60 MaxBonus = 10.1m } "Forge", { Name = "Forge" Boost = "Increase smelt speed" MinCost = 3 BaseEffect = 1.20m PerLevel = 0.10m MaxLevel = 60 MaxBonus = 7.10m } "Aeronautical", { Name = "Aeronautical" Boost = "Increase ship speed" MinCost = 6 BaseEffect = 1.50m PerLevel = 0.25m MaxLevel = 60 MaxBonus = 16.25m } "Astronomy", { Name = "Astronomy" Boost = "Reduce planet upgrade prices" MinCost = 12 BaseEffect = 0.90m PerLevel = -0.04m MaxLevel = 11 MaxBonus = 0.50m } "Packaging", { Name = "Packaging" Boost = "Increase cargo" MinCost = 21 BaseEffect = 1.50m PerLevel = 0.25m MaxLevel = 60 MaxBonus = 16.25m } "Workshop", { Name = "Workshop" Boost = "Increase craft speed" MinCost = 35 BaseEffect = 1.20m PerLevel = 0.10m MaxLevel = 60 MaxBonus = 7.1m } "Laboratory", { Name = "Laboratory" Boost = "Decrease project cost" MinCost = 56 BaseEffect = 0.90m PerLevel = -0.04m MaxLevel = 11 MaxBonus = 0.50m } "Robotics", { Name = "Robotics" Boost = "Decrease rover time" MinCost = 87 BaseEffect = 0.90m PerLevel = -0.04m MaxLevel = 11 MaxBonus = 0.50m } "Lounge", { Name = "Lounge" Boost = "Increase credits earned" MinCost = 133 BaseEffect = 1.15m PerLevel = 0.05m MaxLevel = 60 MaxBonus = 4.1m } "Backup Generator", { Name = "Backup Generator" Boost = "Increase max idle time" MinCost = 200 BaseEffect = 0.5m // +0:30 PerLevel = 0.5m // +0:30 MaxLevel = 44 MaxBonus = 24.0m // 24 hours } "Terrarium", { Name = "Terrarium" Boost = "Decrease colonization cost" MinCost = 298 BaseEffect = 0.90m PerLevel = -0.04m MaxLevel = 11 MaxBonus = 0.50m } "Underforge", { Name = "Underforge" Boost = "Decrease smelter ingredients" MinCost = 439 BaseEffect = 0.90m PerLevel = -0.04m MaxLevel = 11 MaxBonus = 0.50m } "Dorm", { Name = "Dorm" Boost = "Decrease crafter ingredients" MinCost = 642 BaseEffect = 0.90m PerLevel = -0.04m MaxLevel = 11 MaxBonus = 0.50m } "Probability Drive", { Name = "Probability Drive" Boost = "Enables Surges (50% roll)" MinCost = 934 BaseEffect = 0.0m // T0 PerLevel = 1.0m // +1 MaxLevel = 23 MaxBonus = 23.0m // T23 } "Sales", { Name = "Sales" Boost = "Increase alloy and item value" MinCost = 1351 BaseEffect = 1.15m PerLevel = 0.05m MaxLevel = 60 MaxBonus = 4.1m } "Classroom", { Name = "Classroom" Boost = "All manager bonuses" MinCost = 1946 BaseEffect = 1.15m PerLevel = 0.05m MaxLevel = 60 MaxBonus = 4.1m } "Marketing", { Name = "Marketing" Boost = "Increase market bonuses" MinCost = 2792 BaseEffect = 1.30m PerLevel = 0.10m MaxLevel = 60 MaxBonus = 7.2m } "Planet Relations", { Name = "Planet Relations" Boost = "Colonizing Bonuses" MinCost = 4402 BaseEffect = 1.25m PerLevel = 0.10m MaxLevel = 60 MaxBonus = 7.15m } "Belt Studies", { Name = "Belt Studies" Boost = "Asteroid and debris Value" MinCost = 6586 BaseEffect = 1.25m PerLevel = 0.10m MaxLevel = 60 MaxBonus = 7.15m } "Crew Quarters", { Name = "Crew Quarters" Boost = "Additional 20% roll for surges" MinCost = 9358 BaseEffect = 0.0m // T0 PerLevel = 1.0m // +1 MaxLevel = 23 MaxBonus = 23.0m // T23 } "Eleven Forward", { Name = "Eleven Forward" Boost = "Additional 10% roll for surges" MinCost = 13267 BaseEffect = 0.0m // T0 PerLevel = 1.0m // +1 MaxLevel = 23 MaxBonus = 23.0m // T23 } ] // Research definitions - each research provides specific bonuses let researches = Map [ "Advanced Mining", { Name = "Advanced Mining" Description = "Improves mining efficiency" Multipliers = Map [ "Mining", 1.25m ] Cost = 100 } "Advanced Furnace", { Name = "Advanced Furnace" Description = "Improves smelting speed" Multipliers = Map [ "Smelting", 1.2m ] Cost = 150 } "Efficient Engines", { Name = "Efficient Engines" Description = "Improves ship speed" Multipliers = Map [ "Speed", 1.15m ] Cost = 200 } "Cargo Optimization", { Name = "Cargo Optimization" Description = "Increases cargo capacity" Multipliers = Map [ "Cargo", 1.3m ] Cost = 180 } "Hybrid Mining", { Name = "Hybrid Mining" Description = "Advanced mining techniques" Multipliers = Map [ "Mining", 1.4m ] Cost = 300 } "Super Smelting", { Name = "Super Smelting" Description = "Ultra-fast smelting process" Multipliers = Map [ "Smelting", 1.5m ] Cost = 400 } "Multi-Purpose Research", { Name = "Multi-Purpose Research" Description = "Improves multiple systems" Multipliers = Map [ "Mining", 1.1m "Speed", 1.05m "Cargo", 1.08m ] Cost = 500 } ] // Get research multipliers for a specific set of completed researches let getResearchMultipliers (completedResearches: string list) : PlanetMultiplier = let relevantResearches = completedResearches |> List.choose (fun researchName -> Map.tryFind researchName researches) match relevantResearches with | [] -> { Mining = 1.0m; Speed = 1.0m; Cargo = 1.0m } // No researches completed | _ -> let combinedMultipliers = relevantResearches |> List.fold (fun acc research -> research.Multipliers |> Map.fold (fun accMultipliers statName multiplier -> match statName with | "Mining" -> { accMultipliers with Mining = accMultipliers.Mining * multiplier } | "Speed" -> { accMultipliers with Speed = accMultipliers.Speed * multiplier } | "Cargo" -> { accMultipliers with Cargo = accMultipliers.Cargo * multiplier } | _ -> accMultipliers // Ignore unknown stats like "Smelting" ) acc ) { Mining = 1.0m; Speed = 1.0m; Cargo = 1.0m } combinedMultipliers // Get beacon multipliers for a specific planet let getBeaconMultipliers (beacons: Map<string, Beacon>) (planetNumber: int) : PlanetMultiplier = let applicableBeacons = beacons |> Map.filter (fun _ beacon -> let (start, endPlanet) = beacon.PlanetRange planetNumber >= start && planetNumber <= endPlanet ) |> Map.toList match applicableBeacons with | [] -> { Mining = 1.0m Speed = 1.0m Cargo = 1.0m } // No beacons affect this planet | _ -> let result = applicableBeacons |> List.fold (fun acc (_, beacon) -> { Mining = acc.Mining * beacon.Multipliers.Mining Speed = acc.Speed * beacon.Multipliers.Speed Cargo = acc.Cargo * beacon.Multipliers.Cargo }) { Mining = 1.0m Speed = 1.0m Cargo = 1.0m } result // Get global manager bonuses let getGlobalManagerBonuses (globalManagerBonuses: Map<string, string * decimal>) : PlanetMultiplier = globalManagerBonuses |> Map.fold (fun acc _ (bonusType, value) -> match bonusType.ToLower() with | "mining" -> { acc with Mining = acc.Mining * value } | "speed" -> { acc with Speed = acc.Speed * value } | "cargo" -> { acc with Cargo = acc.Cargo * value } | _ -> acc // Unknown bonus type, ignore ) { Mining = 1.0m; Speed = 1.0m; Cargo = 1.0m } // ============================================================================= // FORMULAS MODULE - Pure calculation functions // ============================================================================= module Formulas = // Base calculation functions (reverse-engineered from actual data) let calculateBaseMiningRate (level: int) : decimal = // Formula: level^2 * 0.0215 (improved coefficient for better accuracy) decimal (level * level) * 0.0215m let calculateBaseShipSpeed (level: int) : decimal = // Formula: level^2 * 0.029 (improved coefficient for better accuracy) decimal (level * level) * 0.029m let calculateBaseCargoSpace (level: int) : int = // Formula: level^2 * 0.24 (improved coefficient for better accuracy) int (decimal (level * level) * 0.24m) // Alternative formulas for testing let calculateBaseMiningRateV2 (level: int) : decimal = // Try: level^2 * 0.0215 (slightly higher coefficient) decimal (level * level) * 0.0215m let calculateBaseShipSpeedV2 (level: int) : decimal = // Try: level^2 * 0.029 (slightly higher coefficient) decimal (level * level) * 0.029m let calculateBaseCargoSpaceV2 (level: int) : int = // Try: level^2 * 0.24 (slightly higher coefficient) int (decimal (level * level) * 0.24m) // Formula testing functions let testFormulaCoefficients () = printfn "=== FORMULA COEFFICIENT TESTING ===" printfn "Testing different coefficients to find optimal values..." printfn "" // Test data points let testPoints = [ (34, 76.62m, "Planet 1 Mining") (25, 43.21m, "Planet 2 Mining") (21, 24.17m, "Planet 3 Mining") ] // Test different mining coefficients let miningCoefficients = [0.0200m; 0.0205m; 0.0210m; 0.0215m; 0.0220m; 0.0225m] printfn "Mining Rate Coefficients:" miningCoefficients |> List.iter (fun coeff -> let totalError = testPoints |> List.sumBy (fun (level, actual, _) -> let calculated = decimal (level * level) * coeff * 3.1005m // Total multiplier let error = abs (calculated - actual) / actual * 100m error ) let avgError = totalError / decimal testPoints.Length printfn " %f: Average error = %F%%" coeff avgError ) printfn "" // Test speed data points let speedTestPoints = [ (16, 15.93m, "Planet 1 Speed") (14, 13.32m, "Planet 2 Speed") (11, 9.86m, "Planet 3 Speed") ] // Test different speed coefficients let speedCoefficients = [0.027m; 0.028m; 0.029m; 0.030m; 0.031m] printfn "Speed Coefficients:" speedCoefficients |> List.iter (fun coeff -> let totalError = speedTestPoints |> List.sumBy (fun (level, actual, _) -> let calculated = decimal (level * level) * coeff * 2.1875m // Total speed multiplier let error = abs (calculated - actual) / actual * 100m error ) let avgError = totalError / decimal speedTestPoints.Length printfn " %f: Average error = %F%%" coeff avgError ) printfn "" // Test cargo data points let cargoTestPoints = [ (16, 75, "Planet 1 Cargo") (14, 62, "Planet 2 Cargo") (11, 45, "Planet 3 Cargo") ] // Test different cargo coefficients let cargoCoefficients = [0.22m; 0.23m; 0.24m; 0.25m; 0.26m] printfn "Cargo Coefficients:" cargoCoefficients |> List.iter (fun coeff -> let totalError = cargoTestPoints |> List.sumBy (fun (level, actual, _) -> let calculated = int (decimal (level * level) * coeff * 1.25m) // Total cargo multiplier let error = abs (decimal calculated - decimal actual) / decimal actual * 100m error ) let avgError = totalError / decimal cargoTestPoints.Length printfn " %f: Average error = %F%%" coeff avgError ) // Calculate room effect at given level let calculateRoomEffect (roomName: string) (level: int) : decimal = match Map.tryFind roomName rooms with | Some room -> if room.Boost.Contains("time") || room.Boost.Contains("Surges") then // Special handling for time-based and surge rooms room.BaseEffect + (room.PerLevel * decimal (level - 1)) else // Standard multiplier rooms room.BaseEffect + (room.PerLevel * decimal (level - 1)) | None -> 1.0m // Get room multiplier for specific boost type let getRoomMultiplier (boostType: string) (roomLevels: Map<string, int>) : decimal = let relevantRooms = rooms |> Map.filter (fun _ room -> room.Boost.ToLower().Contains(boostType.ToLower())) |> Map.toList match relevantRooms with | [] -> 1.0m | _ -> relevantRooms |> List.map (fun (roomName, room) -> let level = Map.tryFind roomName roomLevels |> Option.defaultValue 0 calculateRoomEffect roomName level ) |> List.fold (*) 1.0m // Calculate final stats with all multipliers applied let calculatePlanetStats (planetNumber: int) (miningLevel: int) (speedLevel: int) (cargoLevel: int) (multipliers: Multipliers) (purchasedBonuses: {| MineBoost: decimal |}) (daughtershipMultipliers: {| MiningRate: decimal; ShipSpeed: decimal; Cargo: decimal |}) (beacons: Map<string, Beacon>) : PlanetCalculationResult = let baseMining = calculateBaseMiningRate miningLevel let baseSpeed = calculateBaseShipSpeed speedLevel let baseCargo = calculateBaseCargoSpace cargoLevel // Get room multipliers let miningRoomMultiplier = getRoomMultiplier "mine speed" multipliers.RoomLevels let speedRoomMultiplier = getRoomMultiplier "ship speed" multipliers.RoomLevels let cargoRoomMultiplier = getRoomMultiplier "cargo" multipliers.RoomLevels // Get beacon multipliers for this planet let beaconMultipliers = getBeaconMultipliers beacons planetNumber // Get global manager bonuses let globalManagerMultipliers = getGlobalManagerBonuses multipliers.GlobalManagerBonuses // Get research multipliers let researchMultipliers = getResearchMultipliers multipliers.CompletedResearches // Helper function to filter out neutral modifiers (1.0m) let filterActiveModifiers (modifiers: ModifierSource list) = modifiers |> List.filter (fun mod -> mod.Value <> 1.0m) // Collect mining modifiers (only include those that actually affect the result) let miningModifiers = [ { Name = "Base Mining Rate"; Value = baseMining; Description = $"Level {miningLevel} base rate" } if purchasedBonuses.MineBoost <> 1.0m then { Name = "Mine Boost"; Value = purchasedBonuses.MineBoost; Description = "Purchased mine boost" } if multipliers.MiningRate <> 1.0m then { Name = "Mining Rate Multiplier"; Value = multipliers.MiningRate; Description = "Base mining rate multiplier" } if researchMultipliers.Mining <> 1.0m then { Name = "Research Bonus"; Value = researchMultipliers.Mining; Description = "Completed research bonuses" } if multipliers.ColonizationBonuses.ContainsKey(planetNumber) then let bonus = multipliers.ColonizationBonuses.[planetNumber] if bonus.Mining <> 1.0m then { Name = "Colonization Bonus"; Value = bonus.Mining; Description = $"Planet {planetNumber} colonized" } if miningRoomMultiplier <> 1.0m then { Name = "Engineering Room"; Value = miningRoomMultiplier; Description = "Engineering room bonus" } if beaconMultipliers.Mining <> 1.0m then { Name = "Beacon Bonus"; Value = beaconMultipliers.Mining; Description = $"Beacon bonus for planet {planetNumber}" } if globalManagerMultipliers.Mining <> 1.0m then { Name = "Global Manager Bonus"; Value = globalManagerMultipliers.Mining; Description = "Global manager mining bonus" } if multipliers.Daughtership && daughtershipMultipliers.MiningRate <> 1.0m then { Name = "Daughtership"; Value = daughtershipMultipliers.MiningRate; Description = "Daughtership mining bonus" } ] |> List.filter (fun mod -> mod.Value <> 1.0m) // Collect speed modifiers (only include those that actually affect the result) let speedModifiers = [ { Name = "Base Ship Speed"; Value = baseSpeed; Description = $"Level {speedLevel} base speed" } if multipliers.ShipSpeed <> 1.0m then { Name = "Speed Multiplier"; Value = multipliers.ShipSpeed; Description = "Base speed multiplier" } if researchMultipliers.Speed <> 1.0m then { Name = "Research Bonus"; Value = researchMultipliers.Speed; Description = "Completed research bonuses" } if speedRoomMultiplier <> 1.0m then { Name = "Aeronautical Room"; Value = speedRoomMultiplier; Description = "Aeronautical room bonus" } if beaconMultipliers.Speed <> 1.0m then { Name = "Beacon Bonus"; Value = beaconMultipliers.Speed; Description = $"Beacon bonus for planet {planetNumber}" } if globalManagerMultipliers.Speed <> 1.0m then { Name = "Global Manager Bonus"; Value = globalManagerMultipliers.Speed; Description = "Global manager speed bonus" } if multipliers.Daughtership && daughtershipMultipliers.ShipSpeed <> 1.0m then { Name = "Daughtership"; Value = daughtershipMultipliers.ShipSpeed; Description = "Daughtership speed bonus" } ] |> List.filter (fun mod -> mod.Value <> 1.0m) // Collect cargo modifiers (only include those that actually affect the result) let cargoModifiers = [ { Name = "Base Cargo Space"; Value = decimal baseCargo; Description = $"Level {cargoLevel} base cargo" } if multipliers.Cargo <> 1.0m then { Name = "Cargo Multiplier"; Value = multipliers.Cargo; Description = "Base cargo multiplier" } if researchMultipliers.Cargo <> 1.0m then { Name = "Research Bonus"; Value = researchMultipliers.Cargo; Description = "Completed research bonuses" } if cargoRoomMultiplier <> 1.0m then { Name = "Packaging Room"; Value = cargoRoomMultiplier; Description = "Packaging room bonus" } if beaconMultipliers.Cargo <> 1.0m then { Name = "Beacon Bonus"; Value = beaconMultipliers.Cargo; Description = $"Beacon bonus for planet {planetNumber}" } if globalManagerMultipliers.Cargo <> 1.0m then { Name = "Global Manager Bonus"; Value = globalManagerMultipliers.Cargo; Description = "Global manager cargo bonus" } if multipliers.Daughtership && daughtershipMultipliers.Cargo <> 1.0m then { Name = "Daughtership"; Value = daughtershipMultipliers.Cargo; Description = "Daughtership cargo bonus" } ] |> List.filter (fun mod -> mod.Value <> 1.0m) // Calculate final values (include all bonuses) let finalMiningRate = baseMining * purchasedBonuses.MineBoost * multipliers.MiningRate * researchMultipliers.Mining * (if multipliers.ColonizationBonuses.ContainsKey(planetNumber) then multipliers.ColonizationBonuses.[planetNumber].Mining else 1.0m) * miningRoomMultiplier * beaconMultipliers.Mining * globalManagerMultipliers.Mining * (if multipliers.Daughtership then daughtershipMultipliers.MiningRate else 1.0m) let finalSpeed = baseSpeed * multipliers.ShipSpeed * researchMultipliers.Speed * speedRoomMultiplier * beaconMultipliers.Speed * globalManagerMultipliers.Speed * (if multipliers.Daughtership then daughtershipMultipliers.ShipSpeed else 1.0m) let finalCargo = int (decimal baseCargo * multipliers.Cargo * researchMultipliers.Cargo * cargoRoomMultiplier * beaconMultipliers.Cargo * globalManagerMultipliers.Cargo * (if multipliers.Daughtership then daughtershipMultipliers.Cargo else 1.0m)) { FinalStats = { OrePerSecond = finalMiningRate Speed = finalSpeed Cargo = finalCargo } MiningModifiers = miningModifiers SpeedModifiers = speedModifiers CargoModifiers = cargoModifiers } // ============================================================================= // COMPOSITION MODULE - Combines formulas with user input // ============================================================================= module Composition = // Convenience function using current user settings let calculatePlanetStatsDefault (planetNumber: int) (miningLevel: int) (speedLevel: int) (cargoLevel: int) : PlanetCalculationResult = calculatePlanetStats planetNumber miningLevel speedLevel cargoLevel UserInput.multipliers UserInput.purchasedBonuses UserInput.daughtershipMultipliers UserInput.beacons // ============================================================================= // VALIDATION MODULE - Compare calculated vs actual results // ============================================================================= module Validation = type PlanetValidationResult = { PlanetData: TestData.PlanetTestData Calculated: PlanetCalculationResult Actual: PlanetStats MiningAccuracy: decimal SpeedAccuracy: decimal CargoAccuracy: decimal OverallAccuracy: decimal } type TestCaseValidationResult = { TestCase: TestData.TestCase PlanetResults: PlanetValidationResult list AverageAccuracy: decimal } let validatePlanet (planetData: TestData.PlanetTestData) (testCase: TestData.TestCase) : PlanetValidationResult = let calculated = calculatePlanetStats planetData.PlanetNumber planetData.InputLevels.Mining planetData.InputLevels.ShipSpeed planetData.InputLevels.Cargo testCase.CapturedMultipliers testCase.CapturedPurchasedBonuses testCase.CapturedDaughtershipMultipliers testCase.CapturedBeacons let miningAccuracy = if planetData.ActualResults.OrePerSecond = 0m then 0m else (calculated.FinalStats.OrePerSecond / planetData.ActualResults.OrePerSecond) * 100m let speedAccuracy = if planetData.ActualResults.Speed = 0m then 0m else (calculated.FinalStats.Speed / planetData.ActualResults.Speed) * 100m let cargoAccuracy = if planetData.ActualResults.Cargo = 0 then 0m else (decimal calculated.FinalStats.Cargo / decimal planetData.ActualResults.Cargo) * 100m let overallAccuracy = (miningAccuracy + speedAccuracy + cargoAccuracy) / 3m { PlanetData = planetData Calculated = calculated Actual = planetData.ActualResults MiningAccuracy = miningAccuracy SpeedAccuracy = speedAccuracy CargoAccuracy = cargoAccuracy OverallAccuracy = overallAccuracy } let validateTestCase (testCase: TestData.TestCase) : TestCaseValidationResult = let planetResults = testCase.PlanetData |> List.map (fun planetData -> validatePlanet planetData testCase) let averageAccuracy = planetResults |> List.averageBy (fun result -> result.OverallAccuracy) // Update the test case with new accuracy and formula version let updatedTestCase = { testCase with LastCalculatedAccuracy = Some averageAccuracy FormulaVersion = Some TestData.currentFormulaVersion } { TestCase = updatedTestCase PlanetResults = planetResults AverageAccuracy = averageAccuracy } let validateAllTestCases () : TestCaseValidationResult list = TestData.testCases |> List.map validateTestCase let printValidationResults (results: TestCaseValidationResult list) = printfn "=== VALIDATION RESULTS ===" results |> List.iter (fun testCaseResult -> printfn "Test Case: %s" testCaseResult.TestCase.Description printfn " Test Date: %s" testCaseResult.TestCase.TestDate printfn " Average Accuracy: %f%%" testCaseResult.AverageAccuracy printfn " Captured Settings:" printfn " Research: %A" testCaseResult.TestCase.CapturedMultipliers.CompletedResearches printfn " Rooms: %A" testCaseResult.TestCase.CapturedMultipliers.RoomLevels printfn " Daughtership: %b" testCaseResult.TestCase.CapturedMultipliers.Daughtership printfn "" testCaseResult.PlanetResults |> List.iter (fun planetResult -> printfn " Planet %d:" planetResult.PlanetData.PlanetNumber printfn " Input Levels: Mining=%d, Speed=%d, Cargo=%d" planetResult.PlanetData.InputLevels.Mining planetResult.PlanetData.InputLevels.ShipSpeed planetResult.PlanetData.InputLevels.Cargo printfn " Results:" printfn " Mining: %f (actual: %f) - %f%% accurate" planetResult.Calculated.FinalStats.OrePerSecond planetResult.Actual.OrePerSecond planetResult.MiningAccuracy printfn " Speed: %f (actual: %f) - %f%% accurate" planetResult.Calculated.FinalStats.Speed planetResult.Actual.Speed planetResult.SpeedAccuracy printfn " Cargo: %d (actual: %d) - %f%% accurate" planetResult.Calculated.FinalStats.Cargo planetResult.Actual.Cargo planetResult.CargoAccuracy printfn " Overall: %f%% accurate" planetResult.OverallAccuracy printfn "" ) printfn "---" ) // Accuracy comparison functions type AccuracyComparison = { TestCaseDescription: string PreviousAccuracy: decimal option CurrentAccuracy: decimal AccuracyChange: decimal option FormulaVersion: string option } let compareAccuracyWithPrevious (results: TestCaseValidationResult list) : AccuracyComparison list = results |> List.map (fun result -> let accuracyChange = match result.TestCase.LastCalculatedAccuracy with | Some prevAccuracy -> Some (result.AverageAccuracy - prevAccuracy) | None -> None { TestCaseDescription = result.TestCase.Description PreviousAccuracy = result.TestCase.LastCalculatedAccuracy CurrentAccuracy = result.AverageAccuracy AccuracyChange = accuracyChange FormulaVersion = result.TestCase.FormulaVersion } ) let printAccuracyComparison (comparisons: AccuracyComparison list) = printfn "=== ACCURACY COMPARISON ===" printfn "Formula Version: %s" TestData.currentFormulaVersion printfn "" comparisons |> List.iter (fun comparison -> printfn "Test Case: %s" comparison.TestCaseDescription match comparison.PreviousAccuracy with | Some prevAccuracy -> let change = comparison.AccuracyChange.Value let changeStr = if change > 0m then "+" + change.ToString("F2") else change.ToString("F2") let trend = if change > 0m then "📈 IMPROVED" elif change < 0m then "📉 DECLINED" else "➡️ SAME" printfn " Previous: %F%% (Formula: %s)" prevAccuracy (comparison.FormulaVersion.Value) printfn " Current: %F%% (Formula: %s)" comparison.CurrentAccuracy TestData.currentFormulaVersion printfn " Change: %s%% %s" changeStr trend | None -> printfn " Current: %F%% (Formula: %s) - First calculation" comparison.CurrentAccuracy TestData.currentFormulaVersion printfn "" ) // Overall summary let hasPreviousData = comparisons |> List.exists (fun c -> c.PreviousAccuracy.IsSome) if hasPreviousData then let avgChange = comparisons |> List.choose (fun c -> c.AccuracyChange) |> List.average let trend = if avgChange > 0m then "📈 IMPROVED" elif avgChange < 0m then "📉 DECLINED" else "➡️ SAME" printfn "Overall Average Change: %F%% %s" avgChange trend // ============================================================================= // EXAMPLE USAGE // ============================================================================= module Example = // Example: Calculate planet stats with current user settings let calculatePlanet1 () = let result = Composition.calculatePlanetStatsDefault 1 34 16 16 printfn "Planet 1 (Level 34/16/16):" printfn " Mining: %f ore/sec" result.FinalStats.OrePerSecond printfn " Speed: %f" result.FinalStats.Speed printfn " Cargo: %d" result.FinalStats.Cargo result // Example: Validate all test cases let runValidation () = let results = Validation.validateAllTestCases () Validation.printValidationResults results results // Example: Run validation with accuracy comparison let runValidationWithComparison () = let results = Validation.validateAllTestCases () Validation.printValidationResults results printfn "" let comparisons = Validation.compareAccuracyWithPrevious results Validation.printAccuracyComparison comparisons (results, comparisons) // Example: Test with different user settings let testWithAdvancedMining () = let customMultipliers = { UserInput.multipliers with CompletedResearches = ["Advanced Mining"] } let result = calculatePlanetStats 1 34 16 16 customMultipliers UserInput.purchasedBonuses UserInput.daughtershipMultipliers UserInput.beacons printfn "Planet 1 with Advanced Mining research:" printfn " Mining: %f ore/sec" result.FinalStats.OrePerSecond result // Example: Capture current state as new test case with multiple planets let captureNewTestCase () = // Example: Capture multiple planets with current settings let planetData = [ TestData.createPlanetTestData 1 { Mining = 35; ShipSpeed = 17; Cargo = 17 } { OrePerSecond = 85.5m; Speed = 18.2m; Cargo = 85 } TestData.createPlanetTestData 2 { Mining = 26; ShipSpeed = 15; Cargo = 15 } { OrePerSecond = 48.3m; Speed = 14.8m; Cargo = 68 } ] let newTestCase = TestData.captureCurrentState planetData "Planets 1-2 with Advanced Mining research - after leveling up" printfn "Captured new test case:" printfn " Description: %s" newTestCase.Description printfn " Date: %s" newTestCase.TestDate printfn " Planets: %d" newTestCase.PlanetData.Length newTestCase.PlanetData |> List.iter (fun planet -> printfn " Planet %d: Mining=%d/%d/%d -> %f/%f/%d" planet.PlanetNumber planet.InputLevels.Mining planet.InputLevels.ShipSpeed planet.InputLevels.Cargo planet.ActualResults.OrePerSecond planet.ActualResults.Speed planet.ActualResults.Cargo ) newTestCase // Example: Add new test case to the list let addNewTestCase () = let newTestCase = captureNewTestCase () let updatedTestCases = TestData.addTestCase newTestCase printfn "Added new test case. Total test cases: %d" updatedTestCases.Length updatedTestCases // Example: Test different formula coefficients let testFormulaCoefficients () = Formulas.testFormulaCoefficients() // Example: Try improved formulas let testImprovedFormulas () = printfn "=== TESTING IMPROVED FORMULAS ===" printfn "Based on coefficient analysis, trying optimized formulas..." printfn "" // Let's try the formulas that should give better accuracy let testImprovedMining (level: int) = decimal (level * level) * 0.0215m let testImprovedSpeed (level: int) = decimal (level * level) * 0.029m let testImprovedCargo (level: int) = int (decimal (level * level) * 0.24m) // Test against our data let testData = [ (34, 76.62m, 16, 15.93m, 16, 75) (25, 43.21m, 14, 13.32m, 14, 62) (21, 24.17m, 11, 9.86m, 11, 45) ] testData |> List.iter (fun (miningLevel, miningActual, speedLevel, speedActual, cargoLevel, cargoActual) -> let miningBase = testImprovedMining miningLevel let speedBase = testImprovedSpeed speedLevel let cargoBase = testImprovedCargo cargoLevel let miningFinal = miningBase * 3.1005m let speedFinal = speedBase * 2.1875m let cargoFinal = cargoBase * 1.25m let miningError = abs (miningFinal - miningActual) / miningActual * 100m let speedError = abs (speedFinal - speedActual) / speedActual * 100m let cargoError = abs (decimal cargoFinal - decimal cargoActual) / decimal cargoActual * 100m printfn "Level %d/%d/%d:" miningLevel speedLevel cargoLevel printfn " Mining: %f (actual: %f) - %F%% error" miningFinal miningActual miningError printfn " Speed: %f (actual: %f) - %F%% error" speedFinal speedActual speedError printfn " Cargo: %d (actual: %d) - %F%% error" cargoFinal cargoActual cargoError printfn "" )