Skip to content

Instantly share code, notes, and snippets.

@ImaginaryDevelopment
Last active September 4, 2025 21:24
Show Gist options
  • Save ImaginaryDevelopment/5c8646d229c3acd0ab968349f2c18d1c to your computer and use it in GitHub Desktop.
Save ImaginaryDevelopment/5c8646d229c3acd0ab968349f2c18d1c to your computer and use it in GitHub Desktop.
IdlePlanetMiner spike
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.2.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 =
// 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 =
// 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 ""
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment