94 lines
4.1 KiB
C#
94 lines
4.1 KiB
C#
using NUnit.Framework;
|
|
using ProjectM.Simulation;
|
|
using Unity.Mathematics;
|
|
|
|
namespace ProjectM.Tests
|
|
{
|
|
/// <summary>
|
|
/// Pure-function tests for <see cref="RoomLayoutMath"/> — resolving a map node into a <see cref="RoomPlan"/> and
|
|
/// scattering points within a room's shape. Pins the plan mapping, the depth/type difficulty ramp, the per-type
|
|
/// node density, and (the swept-scatter safety net) that every scattered point lies within its shape footprint.
|
|
/// </summary>
|
|
public class RoomLayoutMathTests
|
|
{
|
|
[Test]
|
|
public void Plan_CopiesNodeFields_AndResolvesArchetype()
|
|
{
|
|
var node = new RunMapNode
|
|
{
|
|
RoomType = RoomTypeId.Reward,
|
|
Biome = RoomBiomeId.Cavern,
|
|
ShapeId = RoomShapeId.Wide,
|
|
NextMask = 1,
|
|
};
|
|
var plan = RoomLayoutMath.Plan(node, layer: 3, roomCount: 8);
|
|
Assert.AreEqual(RoomTypeId.Reward, plan.RoomType);
|
|
Assert.AreEqual(RoomBiomeId.Cavern, plan.Biome);
|
|
Assert.AreEqual(RoomShapeId.Wide, plan.ShapeId);
|
|
Assert.AreEqual(RoomLayoutMath.ShapeRadius(RoomShapeId.Wide), plan.Radius);
|
|
Assert.AreEqual(RoomLayoutMath.BaseNodeCount(RoomTypeId.Reward), plan.NodeCount);
|
|
Assert.AreEqual(RoomLayoutMath.DifficultyEpoch(3, RoomTypeId.Reward), plan.DifficultyEpoch);
|
|
}
|
|
|
|
[Test]
|
|
public void DifficultyEpoch_DeeperIsHarder_EliteAndBossBump()
|
|
{
|
|
Assert.AreEqual(1, RoomLayoutMath.DifficultyEpoch(0, RoomTypeId.Combat), "layer 0 floors at 1");
|
|
Assert.Greater(RoomLayoutMath.DifficultyEpoch(5, RoomTypeId.Combat),
|
|
RoomLayoutMath.DifficultyEpoch(2, RoomTypeId.Combat), "deeper is harder");
|
|
Assert.AreEqual(RoomLayoutMath.DifficultyEpoch(4, RoomTypeId.Combat) + 2,
|
|
RoomLayoutMath.DifficultyEpoch(4, RoomTypeId.Elite), "Elite +2");
|
|
Assert.AreEqual(RoomLayoutMath.DifficultyEpoch(4, RoomTypeId.Combat) + 3,
|
|
RoomLayoutMath.DifficultyEpoch(4, RoomTypeId.Boss), "Boss +3");
|
|
}
|
|
|
|
[Test]
|
|
public void BaseNodeCount_RewardDense_BossMinimal()
|
|
{
|
|
Assert.Greater(RoomLayoutMath.BaseNodeCount(RoomTypeId.Reward),
|
|
RoomLayoutMath.BaseNodeCount(RoomTypeId.Combat), "reward rooms are resource-dense");
|
|
Assert.AreEqual(1, RoomLayoutMath.BaseNodeCount(RoomTypeId.Boss), "boss room is minimal");
|
|
Assert.GreaterOrEqual(RoomLayoutMath.BaseNodeCount(RoomTypeId.Combat), 1);
|
|
}
|
|
|
|
[Test]
|
|
public void ShapeRadius_AllShapesPositive()
|
|
{
|
|
for (byte s = 0; s < RoomShapeId.Count; s++)
|
|
Assert.Greater(RoomLayoutMath.ShapeRadius(s), 0f, $"shape {s}");
|
|
}
|
|
|
|
[Test]
|
|
public void ScatterInShape_AlwaysWithinShapeFootprint()
|
|
{
|
|
var center = new float3(1000f, 1f, 5f); // offset origin (expedition region) + nonzero Y preserved
|
|
for (byte shape = 0; shape < RoomShapeId.Count; shape++)
|
|
{
|
|
var rng = new Random(9871u + shape);
|
|
for (int i = 0; i < 500; i++)
|
|
{
|
|
float3 p = RoomLayoutMath.ScatterInShape(shape, center, i, 500, ref rng);
|
|
Assert.AreEqual(center.y, p.y, 1e-4f, $"shape {shape}: Y preserved");
|
|
Assert.IsTrue(RoomLayoutMath.ContainsPoint(shape, center, p),
|
|
$"shape {shape}: scattered point {p} escaped the footprint");
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ScatterInShape_Deterministic_ForSameSeedSequence()
|
|
{
|
|
var center = new float3(0f, 0f, 0f);
|
|
var a = new Random(4242u);
|
|
var b = new Random(4242u);
|
|
for (int i = 0; i < 50; i++)
|
|
{
|
|
float3 pa = RoomLayoutMath.ScatterInShape(RoomShapeId.Cross, center, i, 50, ref a);
|
|
float3 pb = RoomLayoutMath.ScatterInShape(RoomShapeId.Cross, center, i, 50, ref b);
|
|
Assert.AreEqual(pa.x, pb.x, 1e-6f);
|
|
Assert.AreEqual(pa.z, pb.z, 1e-6f);
|
|
}
|
|
}
|
|
}
|
|
}
|