diff --git a/Micropolis.Core.Test/EngineState.cs b/Micropolis.Core.Test/EngineState.cs new file mode 100644 index 0000000..198caf1 --- /dev/null +++ b/Micropolis.Core.Test/EngineState.cs @@ -0,0 +1,28 @@ +namespace Micropolis.Core.Test +{ + public class EngineState + { + public long CityTime { get; set; } + public int TotalPop { get; set; } + public long TotalFunds { get; set; } + public int ResPop { get; set; } + public int ComPop { get; set; } + public int IndPop { get; set; } + public short ResValve { get; set; } + public short ComValve { get; set; } + public short IndValve { get; set; } + public int CrimeAverage { get; set; } + public int PollutionAverage { get; set; } + public int LandValueAverage { get; set; } + public long RoadFund { get; set; } + public long PoliceFund { get; set; } + public long FireFund { get; set; } + public long RoadSpend { get; set; } + public long PoliceSpend { get; set; } + public long FireSpend { get; set; } + public short PhaseCycle { get; set; } + public ushort[][] Map { get; set; } + public byte[][] PowerGridMap { get; set; } + public string AsciiPowerMap { get; set; } + } +} diff --git a/Micropolis.Core.Test/EngineTests.cs b/Micropolis.Core.Test/EngineTests.cs new file mode 100644 index 0000000..bd835f0 --- /dev/null +++ b/Micropolis.Core.Test/EngineTests.cs @@ -0,0 +1,118 @@ +using MicropolisSharp; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using Xunit; + +namespace Micropolis.Core.Test +{ + public class EngineTests + { + [Fact] + public void RunSimulationAndCaptureState() + { + Micropolis engine = new Micropolis(); + engine.SimInit(); + + string cityPath = "../../../Micropolis.Windows/cities/kobe.cty"; + bool success = engine.LoadCity(cityPath); + Assert.True(success, "Failed to load city file."); + + List history = new List(); + + for (int i = 0; i < 100; i++) + { + engine.SimTick(); + + var state = new EngineState + { + CityTime = engine.CityTime, + TotalPop = engine.TotalPop, + TotalFunds = engine.TotalFunds, + ResPop = engine.ResPop, + ComPop = engine.ComPop, + IndPop = engine.IndPop, + ResValve = engine.ResValve, + ComValve = engine.ComValve, + IndValve = engine.IndValve, + CrimeAverage = engine.CrimeAverage, + PollutionAverage = engine.PollutionAverage, + LandValueAverage = engine.LandValueAverage, + RoadFund = engine.RoadFund, + PoliceFund = engine.PoliceFund, + FireFund = engine.FireFund, + RoadSpend = engine.RoadSpend, + PoliceSpend = engine.PoliceSpend, + FireSpend = engine.FireSpend, + PhaseCycle = engine.PhaseCycle, + Map = ConvertMapToJagged(engine.Map), + PowerGridMap = ConvertPowerGridMapToJagged(engine.PowerGridMap), + AsciiPowerMap = GenerateAsciiPowerMap(engine.PowerGridMap) + }; + + history.Add(state); + } + + var options = new JsonSerializerOptions { WriteIndented = true }; + string jsonString = JsonSerializer.Serialize(history, options); + File.WriteAllText("engine_history.json", jsonString); + } + + private ushort[][] ConvertMapToJagged(ushort[,] map) + { + int width = map.GetLength(0); + int height = map.GetLength(1); + ushort[][] jaggedMap = new ushort[height][]; + + for (int y = 0; y < height; y++) + { + jaggedMap[y] = new ushort[width]; + for (int x = 0; x < width; x++) + { + jaggedMap[y][x] = map[x, y]; + } + } + + return jaggedMap; + } + + private byte[][] ConvertPowerGridMapToJagged(MicropolisSharp.Types.ByteMap1 powerGridMap) + { + var width = powerGridMap.width; + var height = powerGridMap.height; + var data1D = powerGridMap.getBase(); + var jaggedMap = new byte[height][]; + + for (int y = 0; y < height; y++) + { + jaggedMap[y] = new byte[width]; + for (int x = 0; x < width; x++) + { + jaggedMap[y][x] = data1D[x * height + y]; + } + } + + return jaggedMap; + } + + private string GenerateAsciiPowerMap(MicropolisSharp.Types.ByteMap1 powerGridMap) + { + var width = powerGridMap.width; + var height = powerGridMap.height; + var data = powerGridMap.getBase(); + var sb = new System.Text.StringBuilder(); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + var value = data[x * height + y]; + sb.Append(value > 0 ? '#' : ' '); + } + sb.AppendLine(); + } + + return sb.ToString(); + } + } +} diff --git a/Micropolis.Core.Test/Micropolis.Core.Test.csproj b/Micropolis.Core.Test/Micropolis.Core.Test.csproj new file mode 100644 index 0000000..05cbb77 --- /dev/null +++ b/Micropolis.Core.Test/Micropolis.Core.Test.csproj @@ -0,0 +1,27 @@ + + + + net6.0 + enable + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/MicropolisSharp.sln b/MicropolisSharp.sln index b2dd3ab..327ac7d 100644 --- a/MicropolisSharp.sln +++ b/MicropolisSharp.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Micropolis.Core", "Micropol EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Micropolis.Windows", "Micropolis.Windows\Micropolis.Windows.csproj", "{A4F88EA5-F359-404A-A49A-20348A73451B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Micropolis.Core.Test", "Micropolis.Core.Test\Micropolis.Core.Test.csproj", "{86A2AC73-2334-400A-A626-75B7F3469A4B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -31,6 +33,14 @@ Global {A4F88EA5-F359-404A-A49A-20348A73451B}.Release|Any CPU.Build.0 = Release|Any CPU {A4F88EA5-F359-404A-A49A-20348A73451B}.Release|x86.ActiveCfg = Release|Any CPU {A4F88EA5-F359-404A-A49A-20348A73451B}.Release|x86.Build.0 = Release|Any CPU + {86A2AC73-2334-400A-A626-75B7F3469A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86A2AC73-2334-400A-A626-75B7F3469A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86A2AC73-2334-400A-A626-75B7F3469A4B}.Debug|x86.ActiveCfg = Debug|Any CPU + {86A2AC73-2334-400A-A626-75B7F3469A4B}.Debug|x86.Build.0 = Debug|Any CPU + {86A2AC73-2334-400A-A626-75B7F3469A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86A2AC73-2334-400A-A626-75B7F3469A4B}.Release|Any CPU.Build.0 = Release|Any CPU + {86A2AC73-2334-400A-A626-75B7F3469A4B}.Release|x86.ActiveCfg = Release|Any CPU + {86A2AC73-2334-400A-A626-75B7F3469A4B}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE