Files
bd2/go/internal/server/gamedata/gacha_probability_test.go
T
Flechazo 5b5a219dc2 feat(server): add special loot and data-driven gameplay rules
Generate equipment loot atomically, grant random boxes and prevent repeat claims.
Read gacha pools, pity, products, tickets, missions, presets, chapter rewards
and inventory costs from GameData; extend both collaboration UR ticket pools.
Sync owned recipes, configure startup state and calendars in versioned seeds,
and validate unlock tickets and revival talents.
2026-10-04 19:15:59 +08:00

101 lines
2.9 KiB
Go

package gamedata
import "testing"
func TestInfiniteGachaOfficialRateBoundariesAndFiveStarGuarantee(t *testing.T) {
characters := map[uint64]CharacterDesign{
5001: {ID: 500, HP: 100},
4001: {ID: 400, HP: 100},
3001: {ID: 300, HP: 100},
}
design, err := NewInfiniteGachaDesignWithRates(6, []uint64{5001}, []uint64{4001}, []uint64{3001}, characters)
if err != nil {
t.Fatal(err)
}
// The first five pairs are rate roll + pool index. They cover both
// boundaries of 3%, the 14% interval and the start of the 83% interval.
// The final value chooses the guaranteed five-star slot.
draws := []uint64{0, 0, 299, 0, 300, 0, 1699, 0, 1700, 0, 0}
position := 0
roll, err := design.rollWith(func(limit uint64) (uint64, error) {
if position >= len(draws) {
t.Fatal("unexpected extra random draw")
}
value := draws[position]
position++
if value >= limit {
t.Fatalf("draw %d exceeds limit %d", value, limit)
}
return value, nil
})
if err != nil {
t.Fatal(err)
}
want := []uint64{5001, 5001, 4001, 4001, 3001, 5001}
for i := range want {
if roll[i] != want[i] {
t.Fatalf("slot %d=%d want=%d; roll=%v", i, roll[i], want[i], roll)
}
}
if position != len(draws) {
t.Fatalf("used %d random draws, want %d", position, len(draws))
}
}
func TestOfficialPickupRateDefinition(t *testing.T) {
pool := []WeightedCostume{
{Weight: 150, ID: 1},
{Weight: 150, ID: 2},
{Weight: 1400, ID: 3},
{Weight: 8300, ID: 4},
}
if err := validateOfficialPickupRates(pool); err != nil {
t.Fatal(err)
}
pool[0].Weight++
if err := validateOfficialPickupRates(pool); err == nil {
t.Fatal("accepted a pickup rate different from official GameData")
}
}
func TestTenPullGuaranteesGradeFourWhenAllNormalRollsAreGradeThree(t *testing.T) {
gacha := RegularGacha{Grades: map[uint64]uint64{5001: 5, 5002: 5, 4001: 4, 3001: 3, 21201: 5}, Count: 10, Pool: []WeightedCostume{
{Weight: 150, ID: 5001}, {Weight: 150, ID: 5002}, {Weight: 1400, ID: 4001}, {Weight: 8300, ID: 3001},
}}
roll, err := gacha.rollWith(func(limit uint64) (uint64, error) {
if limit == officialRateScale {
return 9999, nil
}
return 0, nil
})
if err != nil {
t.Fatal(err)
}
for i := 0; i < 9; i++ {
if roll[i] != 3001 {
t.Fatalf("slot %d=%d want grade-3", i, roll[i])
}
}
if roll[9] != 4001 {
t.Fatalf("guaranteed slot=%d want grade-4; roll=%v", roll[9], roll)
}
}
func TestFixedPickupTenPullAlwaysStartsWithPickupCostume(t *testing.T) {
gacha := RegularGacha{Grades: map[uint64]uint64{5001: 5, 5002: 5, 4001: 4, 3001: 3, 21201: 5}, Count: 10, FixedCostumeID: 21201, Pool: []WeightedCostume{
{Weight: 300, ID: 5002}, {Weight: 1400, ID: 4001}, {Weight: 8300, ID: 3001},
}}
roll, err := gacha.rollWith(func(limit uint64) (uint64, error) { return limit - 1, nil })
if err != nil {
t.Fatal(err)
}
if len(roll) != 10 || roll[0] != 21201 {
t.Fatalf("roll=%v", roll)
}
for i := 1; i < 10; i++ {
if roll[i] != 3001 {
t.Fatalf("slot %d=%d want grade-3", i, roll[i])
}
}
}