Implement surface safety and powered props
This commit is contained in:
@@ -7,14 +7,14 @@ public sealed class SimulationEngineTests
|
||||
{
|
||||
var level = BuildReadyLevel();
|
||||
|
||||
var next = m_Engine.AdvanceTurn(level);
|
||||
var next = m_Engine.AdvancePulseForDebug(level);
|
||||
var consumer = next.GetProp(new(3, 3));
|
||||
|
||||
Assert.Equal(EConsumerServiceState.Producing, consumer.FuelServiceState);
|
||||
Assert.Equal(EConsumerServiceState.Producing, consumer.WaterServiceState);
|
||||
Assert.Equal(EConsumerServiceState.Producing, consumer.ElectricityServiceState);
|
||||
Assert.Equal(ELevelState.Ready, next.Global.LevelState);
|
||||
Assert.Contains(next.Forecasts, forecast => forecast.Kind == EForecastKind.ReactorReady);
|
||||
Assert.Empty(next.Forecasts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -23,7 +23,7 @@ public sealed class SimulationEngineTests
|
||||
var level = BuildReadyLevel();
|
||||
level = level.SetUnderground(new(5, 3), ECarrierType.Fuel, new() { State = EUndergroundState.Intact });
|
||||
|
||||
var next = m_Engine.AdvanceTurn(level);
|
||||
var next = m_Engine.AdvancePulseForDebug(level);
|
||||
|
||||
Assert.NotEqual(ELevelState.Ready, next.Global.LevelState);
|
||||
}
|
||||
@@ -31,7 +31,7 @@ public sealed class SimulationEngineTests
|
||||
[Fact]
|
||||
public void ReactorActivatesOnlyAtReadyControl()
|
||||
{
|
||||
var level = m_Engine.AdvanceTurn(BuildReadyLevel()) with {
|
||||
var level = m_Engine.AdvancePulseForDebug(BuildReadyLevel()) with {
|
||||
Robot = new() { Position = new(5, 3) }
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ public sealed class SimulationEngineTests
|
||||
level = level.SetUnderground(new(2, 2), ECarrierType.Fuel, new() { State = EUndergroundState.Intact });
|
||||
level = level.SetProp(new(2, 2), new() { Type = EPropType.Consumer, SwitchState = EPropSwitchState.Disabled });
|
||||
|
||||
var next = m_Engine.AdvanceTurn(level);
|
||||
var next = m_Engine.AdvancePulseForDebug(level);
|
||||
var consumer = next.GetProp(new(2, 2));
|
||||
|
||||
Assert.Equal(EConsumerServiceState.Disabled, consumer.FuelServiceState);
|
||||
@@ -83,6 +83,42 @@ public sealed class SimulationEngineTests
|
||||
Assert.Equal(Balancing.Current.StepsPerPulse, next.Global.Step);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnpoweredDoorInteractionChangesNoDoorStateButStillPulses()
|
||||
{
|
||||
var level = DoorLevel(powered: false) with { Robot = new() { Position = new(3, 2) } };
|
||||
|
||||
var next = m_Engine.InteractProp(level);
|
||||
|
||||
Assert.Equal(EDoorState.Closed, next.GetProp(new(3, 2)).DoorState);
|
||||
Assert.Equal(1, next.Global.Pulse);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PoweredTerminalInteractionEnablesLocalForecastsUntilRobotLeaves()
|
||||
{
|
||||
var level = TerminalLevel();
|
||||
|
||||
var activated = m_Engine.InteractProp(level);
|
||||
var moved = m_Engine.MoveRobot(activated, new(2, 1));
|
||||
|
||||
Assert.True(activated.GetProp(new(1, 1)).Active);
|
||||
Assert.NotEmpty(activated.Forecasts);
|
||||
Assert.Empty(moved.Forecasts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnpoweredTerminalInteractionRevealsNothingButStillPulses()
|
||||
{
|
||||
var level = TerminalLevel(false);
|
||||
|
||||
var next = m_Engine.InteractProp(level);
|
||||
|
||||
Assert.False(next.GetProp(new(1, 1)).Active);
|
||||
Assert.Empty(next.Forecasts);
|
||||
Assert.Equal(1, next.Global.Pulse);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EveryAcceptedLengthyActionAdvancesOneFixedPulse()
|
||||
{
|
||||
@@ -138,7 +174,7 @@ public sealed class SimulationEngineTests
|
||||
var level = DoorLevel();
|
||||
level = level.SetSurface(new(3, 2), new() { Heat = 8 });
|
||||
|
||||
var next = m_Engine.AdvanceTurn(level);
|
||||
var next = m_Engine.AdvancePulseForDebug(level);
|
||||
|
||||
Assert.Equal(0, next.GetSurface(new(4, 2)).Heat);
|
||||
}
|
||||
@@ -153,7 +189,7 @@ public sealed class SimulationEngineTests
|
||||
StructuralIntegrity = Balancing.Current.StructuralIntegrityLeakThreshold
|
||||
});
|
||||
|
||||
var next = m_Engine.AdvanceTurn(level);
|
||||
var next = m_Engine.AdvancePulseForDebug(level);
|
||||
|
||||
Assert.Equal(EUndergroundState.Leaking, next.GetUnderground(new(2, 2), ECarrierType.Fuel).State);
|
||||
Assert.Contains(next.Leaks, leak => leak.Carrier == ECarrierType.Fuel && leak.UndergroundPosition == new GridPosition(2, 2));
|
||||
@@ -170,7 +206,7 @@ public sealed class SimulationEngineTests
|
||||
StructuralIntegrity = Balancing.Current.MaxStructuralIntegrity - 1
|
||||
});
|
||||
|
||||
var next = m_Engine.AdvanceTurn(level);
|
||||
var next = m_Engine.AdvancePulseForDebug(level);
|
||||
|
||||
Assert.True(next.GetUnderground(new(2, 2), ECarrierType.Fuel).StructuralIntegrity < Balancing.Current.MaxStructuralIntegrity - 1);
|
||||
}
|
||||
@@ -221,17 +257,107 @@ public sealed class SimulationEngineTests
|
||||
Robot = new() { Position = new(2, 2), HeatImmunitySteps = 1 }
|
||||
};
|
||||
|
||||
var next = m_Engine.AdvanceTurn(level);
|
||||
var next = m_Engine.AdvancePulseForDebug(level);
|
||||
|
||||
Assert.NotEqual(ELevelState.Lost, next.Global.LevelState);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnsafeEntryLossOnlyHappensWhenMovingIntoUnsafeDestination()
|
||||
{
|
||||
var level = LevelState.Create("Unsafe", 5, 5) with { Robot = new() { Position = new(1, 1) } };
|
||||
level = level.SetSurface(new(2, 1), new() { Heat = Balancing.Current.RobotHeatSafetyThreshold });
|
||||
|
||||
var next = m_Engine.MoveRobot(level, new(2, 1));
|
||||
|
||||
Assert.Equal(ELevelState.Lost, next.Global.LevelState);
|
||||
Assert.Equal("UNSAFE ENTRY LOSS", next.Global.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FuelOnlyAndWaterOnlyCellsAreSafeToEnter()
|
||||
{
|
||||
var fuel = LevelState.Create("Fuel safe", 5, 5) with { Robot = new() { Position = new(1, 1) } };
|
||||
fuel = fuel.SetSurface(new(2, 1), new() { Fuel = Balancing.Current.MaxValue });
|
||||
var water = LevelState.Create("Water safe", 5, 5) with { Robot = new() { Position = new(1, 1) } };
|
||||
water = water.SetSurface(new(2, 1), new() { Water = Balancing.Current.MaxValue });
|
||||
|
||||
Assert.NotEqual(ELevelState.Lost, m_Engine.MoveRobot(fuel, new(2, 1)).Global.LevelState);
|
||||
Assert.NotEqual(ELevelState.Lost, m_Engine.MoveRobot(water, new(2, 1)).Global.LevelState);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PulseDoesNotLoseStationaryRobotWhenCellBecomesUnsafe()
|
||||
{
|
||||
var level = LevelState.Create("Stationary", 5, 5) with { Robot = new() { Position = new(2, 2) } };
|
||||
level = level.SetSurface(new(2, 2), new() { Heat = Balancing.Current.RobotHeatSafetyThreshold });
|
||||
|
||||
var next = m_Engine.AdvancePulseForDebug(level);
|
||||
|
||||
Assert.NotEqual(ELevelState.Lost, next.Global.LevelState);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WaterDilutesFuelAndQuenchesHeatBeforeIgnition()
|
||||
{
|
||||
var level = LevelState.Create("Mitigation", 5, 5);
|
||||
level = level.SetSurface(new(2, 2), new() {
|
||||
Fuel = Balancing.Current.FuelCaution,
|
||||
Water = Balancing.Current.WaterCritical,
|
||||
Heat = Balancing.Current.HeatCaution
|
||||
});
|
||||
|
||||
var next = m_Engine.AdvanceStepForDebug(level);
|
||||
|
||||
Assert.True(next.GetSurface(new(2, 2)).Fuel < level.GetSurface(new(2, 2)).Fuel);
|
||||
Assert.True(next.GetSurface(new(2, 2)).Heat < level.GetSurface(new(2, 2)).Heat);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HotCellsEvaporateWaterFasterThanColdCells()
|
||||
{
|
||||
var level = LevelState.Create("Evaporation", 5, 5);
|
||||
level = level.SetSurface(new(1, 1), new() { Water = 5 });
|
||||
level = level.SetSurface(new(2, 1), new() { Water = 5, Heat = 6 });
|
||||
|
||||
var next = m_Engine.AdvanceStepForDebug(level);
|
||||
|
||||
Assert.True(next.GetSurface(new(2, 1)).Water < next.GetSurface(new(1, 1)).Water);
|
||||
Assert.True(next.GetSurface(new(2, 1)).Heat < 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WetCellsConductElectricityFasterThanDryCells()
|
||||
{
|
||||
var wet = LevelState.Create("Wet conduct", 5, 5);
|
||||
wet = wet.SetSurface(new(1, 1), new() { Electricity = 8, Water = Balancing.Current.WaterCaution });
|
||||
var dry = LevelState.Create("Dry conduct", 5, 5);
|
||||
dry = dry.SetSurface(new(1, 1), new() { Electricity = 8 });
|
||||
|
||||
var wetNext = m_Engine.AdvanceStepForDebug(wet);
|
||||
var dryNext = m_Engine.AdvanceStepForDebug(dry);
|
||||
|
||||
Assert.True(wetNext.GetSurface(new(2, 1)).Electricity > dryNext.GetSurface(new(2, 1)).Electricity);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FuelAndElectricityCanIgniteIntoHeat()
|
||||
{
|
||||
var level = LevelState.Create("Ignite", 5, 5);
|
||||
level = level.SetSurface(new(2, 2), new() { Fuel = Balancing.Current.FuelCritical, Electricity = Balancing.Current.ElectricityCritical });
|
||||
|
||||
var next = m_Engine.AdvanceStepForDebug(level);
|
||||
|
||||
Assert.True(next.GetSurface(new(2, 2)).Heat > 0);
|
||||
Assert.True(next.GetSurface(new(2, 2)).Fuel < level.GetSurface(new(2, 2)).Fuel);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JunctionRatioSplitsFlowAcrossInferredOutgoingBranches()
|
||||
{
|
||||
var level = BuildJunctionLevel(2);
|
||||
|
||||
var next = m_Engine.AdvanceTurn(level);
|
||||
var next = m_Engine.AdvancePulseForDebug(level);
|
||||
|
||||
Assert.True(next.GetUnderground(new(2, 2), ECarrierType.Fuel).Amount > 0);
|
||||
Assert.Equal(next.GetUnderground(new(2, 2), ECarrierType.Fuel).Amount, next.GetUnderground(new(3, 3), ECarrierType.Fuel).Amount);
|
||||
@@ -243,7 +369,7 @@ public sealed class SimulationEngineTests
|
||||
{
|
||||
var level = BuildJunctionLevel(0);
|
||||
|
||||
var next = m_Engine.AdvanceTurn(level);
|
||||
var next = m_Engine.AdvancePulseForDebug(level);
|
||||
|
||||
Assert.Equal(0, next.GetUnderground(new(2, 2), ECarrierType.Fuel).Amount);
|
||||
Assert.True(next.GetUnderground(new(3, 3), ECarrierType.Fuel).Amount > 0);
|
||||
@@ -393,11 +519,17 @@ public sealed class SimulationEngineTests
|
||||
};
|
||||
}
|
||||
|
||||
private static LevelState DoorLevel(LevelState? seed = null)
|
||||
private static LevelState DoorLevel(LevelState? seed = null, bool powered = true)
|
||||
{
|
||||
var level = seed ?? LevelState.Create("Door", 6, 6);
|
||||
level = level.SetTerrain(new(3, 1), ECellTerrain.Wall);
|
||||
level = level.SetTerrain(new(3, 3), ECellTerrain.Wall);
|
||||
if (powered)
|
||||
{
|
||||
level = AddLine(level, ECarrierType.Electricity, new(2, 2), new(3, 2));
|
||||
level = level.SetProp(new(2, 2), new() { Type = EPropType.Flow, Carrier = ECarrierType.Electricity });
|
||||
}
|
||||
|
||||
return level.SetProp(new(3, 2), new() { Type = EPropType.Door, DoorState = EDoorState.Closed });
|
||||
}
|
||||
|
||||
@@ -453,5 +585,19 @@ public sealed class SimulationEngineTests
|
||||
};
|
||||
}
|
||||
|
||||
private static LevelState TerminalLevel(bool powered = true)
|
||||
{
|
||||
var level = BuildReadyLevel();
|
||||
level = level.SetProp(new(1, 1), new() { Type = EPropType.AllSeeingEyeTerminal });
|
||||
level = level.SetUnderground(new(1, 1), ECarrierType.Electricity, new() { State = EUndergroundState.Intact });
|
||||
if (powered)
|
||||
{
|
||||
level = level.SetUnderground(new(1, 2), ECarrierType.Electricity, new() { State = EUndergroundState.Intact });
|
||||
level = level.SetProp(new(1, 2), new() { Type = EPropType.Flow, Carrier = ECarrierType.Electricity });
|
||||
}
|
||||
|
||||
return level with { Robot = new() { Position = new(1, 1) } };
|
||||
}
|
||||
|
||||
private readonly SimulationEngine m_Engine = new();
|
||||
}
|
||||
Reference in New Issue
Block a user