test(packs): statistical sampler + mark PackRateConfig [Obsolete]
200k-slot statistical test asserts observed tier rates within +/- 0.5pp
of the seeded SV Classic shape (Bronze=76.5 / Silver=16 / Gold=6 /
Legendary=1.5 on general slots). Marked [Category("Slow")].
PackRateConfig is marked [Obsolete] — no longer consulted by
PackOpenService. Internal callers (GameConfigService / DbContext config
seeding / its own tests) still reference it; they'll go when v1
stabilizes and PackRateConfig is fully retired.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -139,6 +139,62 @@ public class PackOpenServiceTests
|
||||
Assert.That(bonus.CardId, Is.AnyOf(300L, 301L));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Category("Slow")]
|
||||
public void Draw_observed_tier_rates_track_seed_within_half_a_percent()
|
||||
{
|
||||
// Synthetic Classic pack: Bronze=76.5/Silver=16/Gold=6/Legendary=1.5 in general slots;
|
||||
// slot 8 is Silver=92.5/Gold=6/Legendary=1.5 (no Bronze).
|
||||
var table = new PackDrawTable
|
||||
{
|
||||
Config = new PackDrawConfigEntry { Id = 10000, AnimationRatePct = 0 },
|
||||
SlotRates = new[]
|
||||
{
|
||||
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Bronze, RatePct = 76.5 },
|
||||
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Silver, RatePct = 16.0 },
|
||||
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Gold, RatePct = 6.0 },
|
||||
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Legendary, RatePct = 1.5 },
|
||||
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.Eighth, Tier = DrawTier.Silver, RatePct = 92.5 },
|
||||
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.Eighth, Tier = DrawTier.Gold, RatePct = 6.0 },
|
||||
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.Eighth, Tier = DrawTier.Legendary, RatePct = 1.5 },
|
||||
},
|
||||
CardWeights = new[]
|
||||
{
|
||||
new PackDrawCardWeightEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Bronze, CardId = 1, RatePct = 76.5 },
|
||||
new PackDrawCardWeightEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Silver, CardId = 2, RatePct = 16.0 },
|
||||
new PackDrawCardWeightEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Gold, CardId = 3, RatePct = 6.0 },
|
||||
new PackDrawCardWeightEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Legendary, CardId = 4, RatePct = 1.5 },
|
||||
},
|
||||
};
|
||||
var svc = new PackOpenService();
|
||||
var rng = new SystemRandom(42);
|
||||
var pack = new PackConfigEntry { Id = 10000 };
|
||||
int totalSlots = 200_000;
|
||||
int bronze = 0, silver = 0, gold = 0, legendary = 0;
|
||||
|
||||
// 25_000 packs * 7 general slots = 175_000 general-slot observations.
|
||||
for (int i = 0; i < totalSlots / 8; i++)
|
||||
{
|
||||
var r = svc.Draw(table, pack, 1, Array.Empty<long>(), Array.Empty<long>(), new NoFoil(), rng);
|
||||
for (int s = 0; s < 7; s++)
|
||||
{
|
||||
switch (r.Cards[s].Rarity)
|
||||
{
|
||||
case Rarity.Bronze: bronze++; break;
|
||||
case Rarity.Silver: silver++; break;
|
||||
case Rarity.Gold: gold++; break;
|
||||
case Rarity.Legendary: legendary++; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double n = bronze + silver + gold + legendary;
|
||||
Assert.That(100 * bronze / n, Is.EqualTo(76.5).Within(0.5));
|
||||
Assert.That(100 * silver / n, Is.EqualTo(16.0).Within(0.5));
|
||||
Assert.That(100 * gold / n, Is.EqualTo(6.0).Within(0.5));
|
||||
Assert.That(100 * legendary / n, Is.EqualTo(1.5).Within(0.5));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Draw_does_not_emit_bonus_for_packNumber_less_than_10()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user