From 3c5fc60ffe2ac5443f852b94c7a414acd7d9a602 Mon Sep 17 00:00:00 2001 From: Frank Tovar Date: Sun, 10 May 2026 18:07:16 +0200 Subject: [PATCH] Parameterize surface interactions --- .../Balancing.cs | 95 ++++++++++++++++--- .../Difficulties/NormalBalancing.cs | 25 +++-- .../Models/EPairEffect.cs | 19 ---- .../Models/ESurfaceInteractionVerb.cs | 11 +++ .../Models/ESurfaceQuantity.cs | 9 ++ .../SimulationEngine.cs | 93 +++++------------- .../SurfaceInteractionEffect.cs | 11 +++ 7 files changed, 150 insertions(+), 113 deletions(-) delete mode 100644 src/ReactorMaintenance.Simulation/Models/EPairEffect.cs create mode 100644 src/ReactorMaintenance.Simulation/Models/ESurfaceInteractionVerb.cs create mode 100644 src/ReactorMaintenance.Simulation/Models/ESurfaceQuantity.cs create mode 100644 src/ReactorMaintenance.Simulation/SurfaceInteractionEffect.cs diff --git a/src/ReactorMaintenance.Simulation/Balancing.cs b/src/ReactorMaintenance.Simulation/Balancing.cs index d4c6536..601ba35 100644 --- a/src/ReactorMaintenance.Simulation/Balancing.cs +++ b/src/ReactorMaintenance.Simulation/Balancing.cs @@ -37,6 +37,76 @@ public abstract class Balancing return ratios[Math.Clamp(mode, 0, ratios.Count - 1)].Weights; } + public SurfaceInteractionEffect SameCellInteraction(ECarrierType? rowCarrier, EBand rowBand, ECarrierType? colCarrier, EBand colBand) + { + if (rowBand == EBand.Safe && colBand == EBand.Safe) + return SurfaceInteractionEffect.Hold; + + if (rowCarrier == ECarrierType.Fuel && colCarrier == ECarrierType.Electricity) + return Ignite(rowBand, colBand); + + if (rowCarrier == ECarrierType.Fuel && colCarrier is null) + return rowBand == EBand.Critical || colBand == EBand.Critical ? Ignite(rowBand, colBand) : Warm(rowBand, colBand); + + if (rowCarrier == ECarrierType.Coolant && colCarrier == ECarrierType.Electricity) + return Short(rowBand, colBand); + + if (rowCarrier == ECarrierType.Coolant && colCarrier is null) + return Quench(rowBand, colBand); + + return SurfaceInteractionEffect.Hold; + } + + public SurfaceInteractionEffect FlowInteraction(ESurfaceQuantity quantity) + { + return new() { Verb = ESurfaceInteractionVerb.Flow, Quantity = quantity, Amount = FlowTransferRatio }; + } + + private SurfaceInteractionEffect Warm(EBand rowBand, EBand colBand) + { + return new() { + Verb = ESurfaceInteractionVerb.Warm, + Quantity = ESurfaceQuantity.Heat, + Amount = Strongest(rowBand, colBand) == EBand.Critical ? WarmCriticalAmount : WarmCautionAmount + }; + } + + private SurfaceInteractionEffect Quench(EBand rowBand, EBand colBand) + { + return new() { + Verb = ESurfaceInteractionVerb.Quench, + Quantity = ESurfaceQuantity.Heat, + Amount = Strongest(rowBand, colBand) == EBand.Critical ? QuenchCriticalAmount : QuenchCautionAmount + }; + } + + private SurfaceInteractionEffect Short(EBand rowBand, EBand colBand) + { + var critical = Strongest(rowBand, colBand) == EBand.Critical; + return new() { + Verb = ESurfaceInteractionVerb.Short, + Quantity = ESurfaceQuantity.Electricity, + Amount = critical ? ShortCriticalHeat : ShortCautionHeat, + SecondaryAmount = critical ? ShortCriticalDischarge : ShortCautionDischarge + }; + } + + private SurfaceInteractionEffect Ignite(EBand rowBand, EBand colBand) + { + var critical = Strongest(rowBand, colBand) == EBand.Critical; + return new() { + Verb = ESurfaceInteractionVerb.Ignite, + Quantity = ESurfaceQuantity.Fuel, + Amount = critical ? IgniteCriticalHeat : IgniteCautionHeat, + SecondaryAmount = critical ? IgniteCriticalFuelConsumption : IgniteCautionFuelConsumption + }; + } + + private static EBand Strongest(EBand a, EBand b) + { + return a > b ? a : b; + } + public abstract int DefaultLevelWidth { get; } public abstract int DefaultLevelHeight { get; } public abstract int MinimumLevelSize { get; } @@ -73,19 +143,18 @@ public abstract class Balancing public abstract float LeakAmountScale { get; } public abstract float LeakIntensityScale { get; } public abstract float FlowTransferRatio { get; } - public abstract float StrongFlowTransferRatio { get; } - public abstract float Warm1Amount { get; } - public abstract float Warm2Amount { get; } - public abstract float Quench1Amount { get; } - public abstract float Quench2Amount { get; } - public abstract float Short1Heat { get; } - public abstract float Short1Discharge { get; } - public abstract float Short2Heat { get; } - public abstract float Short2Discharge { get; } - public abstract float Ignite1Heat { get; } - public abstract float Ignite1FuelConsumption { get; } - public abstract float Ignite2Heat { get; } - public abstract float Ignite2FuelConsumption { get; } + public abstract float WarmCautionAmount { get; } + public abstract float WarmCriticalAmount { get; } + public abstract float QuenchCautionAmount { get; } + public abstract float QuenchCriticalAmount { get; } + public abstract float ShortCautionHeat { get; } + public abstract float ShortCautionDischarge { get; } + public abstract float ShortCriticalHeat { get; } + public abstract float ShortCriticalDischarge { get; } + public abstract float IgniteCautionHeat { get; } + public abstract float IgniteCautionFuelConsumption { get; } + public abstract float IgniteCriticalHeat { get; } + public abstract float IgniteCriticalFuelConsumption { get; } public abstract int RemedyBlockTurns { get; } public abstract int HeatShieldSteps { get; } public abstract int InventoryCapacityPerRemedy { get; } diff --git a/src/ReactorMaintenance.Simulation/Difficulties/NormalBalancing.cs b/src/ReactorMaintenance.Simulation/Difficulties/NormalBalancing.cs index 4338e8f..d73c1b6 100644 --- a/src/ReactorMaintenance.Simulation/Difficulties/NormalBalancing.cs +++ b/src/ReactorMaintenance.Simulation/Difficulties/NormalBalancing.cs @@ -49,19 +49,18 @@ public class NormalBalancing : Balancing public override float LeakAmountScale => 0.15f; public override float LeakIntensityScale => 0.1f; public override float FlowTransferRatio => 0.05f; - public override float StrongFlowTransferRatio => 0.1f; - public override float Warm1Amount => 0.5f; - public override float Warm2Amount => 1.0f; - public override float Quench1Amount => 0.6f; - public override float Quench2Amount => 1.2f; - public override float Short1Heat => 0.8f; - public override float Short1Discharge => 0.8f; - public override float Short2Heat => 1.6f; - public override float Short2Discharge => 1.5f; - public override float Ignite1Heat => 1.2f; - public override float Ignite1FuelConsumption => 0.4f; - public override float Ignite2Heat => 2.4f; - public override float Ignite2FuelConsumption => 0.8f; + public override float WarmCautionAmount => 0.5f; + public override float WarmCriticalAmount => 1.0f; + public override float QuenchCautionAmount => 0.6f; + public override float QuenchCriticalAmount => 1.2f; + public override float ShortCautionHeat => 0.8f; + public override float ShortCautionDischarge => 0.8f; + public override float ShortCriticalHeat => 1.6f; + public override float ShortCriticalDischarge => 1.5f; + public override float IgniteCautionHeat => 1.2f; + public override float IgniteCautionFuelConsumption => 0.4f; + public override float IgniteCriticalHeat => 2.4f; + public override float IgniteCriticalFuelConsumption => 0.8f; public override int RemedyBlockTurns => 2; public override int HeatShieldSteps => 3; public override int InventoryCapacityPerRemedy => 3; diff --git a/src/ReactorMaintenance.Simulation/Models/EPairEffect.cs b/src/ReactorMaintenance.Simulation/Models/EPairEffect.cs deleted file mode 100644 index dcf896f..0000000 --- a/src/ReactorMaintenance.Simulation/Models/EPairEffect.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace ReactorMaintenance.Simulation; - -public enum EPairEffect -{ - Hold, - FuelFlow, - CoolFlow, - ChargeFlow, - HeatFlow, - HeatFlow2, - Warm1, - Warm2, - Quench1, - Quench2, - Short1, - Short2, - Ignite1, - Ignite2 -} diff --git a/src/ReactorMaintenance.Simulation/Models/ESurfaceInteractionVerb.cs b/src/ReactorMaintenance.Simulation/Models/ESurfaceInteractionVerb.cs new file mode 100644 index 0000000..51da4d6 --- /dev/null +++ b/src/ReactorMaintenance.Simulation/Models/ESurfaceInteractionVerb.cs @@ -0,0 +1,11 @@ +namespace ReactorMaintenance.Simulation; + +public enum ESurfaceInteractionVerb +{ + Hold, + Flow, + Warm, + Quench, + Short, + Ignite +} diff --git a/src/ReactorMaintenance.Simulation/Models/ESurfaceQuantity.cs b/src/ReactorMaintenance.Simulation/Models/ESurfaceQuantity.cs new file mode 100644 index 0000000..adbe589 --- /dev/null +++ b/src/ReactorMaintenance.Simulation/Models/ESurfaceQuantity.cs @@ -0,0 +1,9 @@ +namespace ReactorMaintenance.Simulation; + +public enum ESurfaceQuantity +{ + Fuel, + Coolant, + Electricity, + Heat +} diff --git a/src/ReactorMaintenance.Simulation/SimulationEngine.cs b/src/ReactorMaintenance.Simulation/SimulationEngine.cs index 9e4f001..2b03c6e 100644 --- a/src/ReactorMaintenance.Simulation/SimulationEngine.cs +++ b/src/ReactorMaintenance.Simulation/SimulationEngine.cs @@ -296,107 +296,64 @@ public sealed class SimulationEngine { var surfaceA = level.GetSurface(a); var surfaceB = level.GetSurface(b); - FlowBetween(level, a, b, surfaceA.Fuel, surfaceB.Fuel, EPairEffect.FuelFlow, deltas); - FlowBetween(level, a, b, surfaceA.Coolant, surfaceB.Coolant, EPairEffect.CoolFlow, deltas); - FlowBetween(level, a, b, surfaceA.Electricity, surfaceB.Electricity, EPairEffect.ChargeFlow, deltas); - FlowBetween(level, a, b, surfaceA.Heat, surfaceB.Heat, EPairEffect.HeatFlow, deltas); + FlowBetween(level, a, b, surfaceA.Fuel, surfaceB.Fuel, Balancing.Current.FlowInteraction(ESurfaceQuantity.Fuel), deltas); + FlowBetween(level, a, b, surfaceA.Coolant, surfaceB.Coolant, Balancing.Current.FlowInteraction(ESurfaceQuantity.Coolant), deltas); + FlowBetween(level, a, b, surfaceA.Electricity, surfaceB.Electricity, Balancing.Current.FlowInteraction(ESurfaceQuantity.Electricity), deltas); + FlowBetween(level, a, b, surfaceA.Heat, surfaceB.Heat, Balancing.Current.FlowInteraction(ESurfaceQuantity.Heat), deltas); } private static void ApplyPair(LevelState level, GridPosition a, GridPosition b, ECarrierType? rowCarrier, EBand rowBand, ECarrierType? colCarrier, EBand colBand, SurfaceDelta[] deltas) { - ApplyEffect(level, a, b, PairEffect(rowCarrier, rowBand, colCarrier, colBand), deltas); + ApplyEffect(level, a, Balancing.Current.SameCellInteraction(rowCarrier, rowBand, colCarrier, colBand), deltas); } - private static EPairEffect PairEffect(ECarrierType? rowCarrier, EBand rowBand, ECarrierType? colCarrier, EBand colBand) + private static void ApplyEffect(LevelState level, GridPosition position, SurfaceInteractionEffect effect, SurfaceDelta[] deltas) { - if (rowBand == EBand.Safe && colBand == EBand.Safe) - return EPairEffect.Hold; - - if (rowCarrier == colCarrier) - return rowCarrier switch { - ECarrierType.Fuel => EPairEffect.FuelFlow, - ECarrierType.Coolant => EPairEffect.CoolFlow, - ECarrierType.Electricity => EPairEffect.ChargeFlow, - _ => EPairEffect.HeatFlow - }; - - if (rowCarrier == ECarrierType.Fuel && colCarrier == ECarrierType.Electricity) - return rowBand == EBand.Critical || colBand == EBand.Critical ? EPairEffect.Ignite2 : EPairEffect.Ignite1; - - if (rowCarrier == ECarrierType.Fuel && colCarrier is null) - return rowBand == EBand.Critical || colBand == EBand.Critical ? EPairEffect.Ignite2 : EPairEffect.Warm1; - - if (rowCarrier == ECarrierType.Coolant && colCarrier == ECarrierType.Electricity) - return rowBand == EBand.Critical || colBand == EBand.Critical ? EPairEffect.Short2 : EPairEffect.Short1; - - if (rowCarrier == ECarrierType.Coolant && colCarrier is null) - return rowBand == EBand.Critical || colBand == EBand.Critical ? EPairEffect.Quench2 : EPairEffect.Quench1; - - return EPairEffect.Hold; - } - - private static void ApplyEffect(LevelState level, GridPosition a, GridPosition b, EPairEffect effect, SurfaceDelta[] deltas) - { - var index = level.Index(a); - switch (effect) + var index = level.Index(position); + switch (effect.Verb) { - case EPairEffect.Warm1: - deltas[index].Heat += Balancing.Current.Warm1Amount; + case ESurfaceInteractionVerb.Warm: + deltas[index].Heat += effect.Amount; break; - case EPairEffect.Warm2: - deltas[index].Heat += Balancing.Current.Warm2Amount; + case ESurfaceInteractionVerb.Quench: + deltas[index].Heat -= effect.Amount; break; - case EPairEffect.Quench1: - deltas[index].Heat -= Balancing.Current.Quench1Amount; + case ESurfaceInteractionVerb.Short: + deltas[index].Heat += effect.Amount; + deltas[index].Electricity -= effect.SecondaryAmount; break; - case EPairEffect.Quench2: - deltas[index].Heat -= Balancing.Current.Quench2Amount; - break; - case EPairEffect.Short1: - deltas[index].Heat += Balancing.Current.Short1Heat; - deltas[index].Electricity -= Balancing.Current.Short1Discharge; - break; - case EPairEffect.Short2: - deltas[index].Heat += Balancing.Current.Short2Heat; - deltas[index].Electricity -= Balancing.Current.Short2Discharge; - break; - case EPairEffect.Ignite1: - deltas[index].Heat += Balancing.Current.Ignite1Heat; - deltas[index].Fuel -= Balancing.Current.Ignite1FuelConsumption; - break; - case EPairEffect.Ignite2: - deltas[index].Heat += Balancing.Current.Ignite2Heat; - deltas[index].Fuel -= Balancing.Current.Ignite2FuelConsumption; + case ESurfaceInteractionVerb.Ignite: + deltas[index].Heat += effect.Amount; + deltas[index].Fuel -= effect.SecondaryAmount; break; } } - private static void FlowBetween(LevelState level, GridPosition a, GridPosition b, float valueA, float valueB, EPairEffect effect, SurfaceDelta[] deltas) + private static void FlowBetween(LevelState level, GridPosition a, GridPosition b, float valueA, float valueB, SurfaceInteractionEffect effect, SurfaceDelta[] deltas) { var difference = valueA - valueB; if (Math.Abs(difference) < 0.01f) return; - var amount = difference * (effect == EPairEffect.HeatFlow2 ? Balancing.Current.StrongFlowTransferRatio : Balancing.Current.FlowTransferRatio); + var amount = difference * effect.Amount; var indexA = level.Index(a); var indexB = level.Index(b); - switch (effect) + switch (effect.Quantity) { - case EPairEffect.FuelFlow: + case ESurfaceQuantity.Fuel: deltas[indexA].Fuel -= amount; deltas[indexB].Fuel += amount; break; - case EPairEffect.CoolFlow: + case ESurfaceQuantity.Coolant: deltas[indexA].Coolant -= amount; deltas[indexB].Coolant += amount; break; - case EPairEffect.ChargeFlow: + case ESurfaceQuantity.Electricity: deltas[indexA].Electricity -= amount; deltas[indexB].Electricity += amount; break; - case EPairEffect.HeatFlow: - case EPairEffect.HeatFlow2: + case ESurfaceQuantity.Heat: deltas[indexA].Heat -= amount; deltas[indexB].Heat += amount; break; diff --git a/src/ReactorMaintenance.Simulation/SurfaceInteractionEffect.cs b/src/ReactorMaintenance.Simulation/SurfaceInteractionEffect.cs new file mode 100644 index 0000000..038d71a --- /dev/null +++ b/src/ReactorMaintenance.Simulation/SurfaceInteractionEffect.cs @@ -0,0 +1,11 @@ +namespace ReactorMaintenance.Simulation; + +public sealed record SurfaceInteractionEffect +{ + public static SurfaceInteractionEffect Hold { get; } = new(); + + public ESurfaceInteractionVerb Verb { get; init; } + public ESurfaceQuantity Quantity { get; init; } + public float Amount { get; init; } + public float SecondaryAmount { get; init; } +}