У меня довольно сложное приложение Go. Он генерирует много случайных результатов в длинной цепочке. Он засевается только один раз - когда приходит HTTP-запрос.
Независимо от того, что такое начальное число - будь то время Unix или моя собственная буквенно-цифровая функция начального числа - оно всегда генерирует полностьюслучайные результаты.
Я пытался отключить буквенно-цифровую функцию заполнения, но это не меняет поведение. Я также пытался установить начальное значение всегда на 1111. Это не имеет никакого эффекта.
Вот пример (подробный и взятый непосредственно из источника, так как это то, что было запрошено):
func main() {
sentryDSN := os.Getenv("SENTRY_DSN")
sentry.Init(sentry.ClientOptions{
Dsn: sentryDSN,
})
sentryHandler := sentryhttp.New(sentryhttp.Options{
Repanic: true,
})
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.URLFormat)
r.Use(middleware.SetHeader("Content-Type", "application/json"))
r.Use(middleware.Timeout(60 * time.Second))
r.Get("/buildingstyle", sentryHandler.HandleFunc(getBuildingStyleRandom))
r.Get("/buildingstyle/{id}", sentryHandler.HandleFunc(getBuildingStyle))
r.Get("/character", sentryHandler.HandleFunc(getCharacterRandom))
r.Get("/character/{id}", sentryHandler.HandleFunc(getCharacter))
r.Get("/climate", sentryHandler.HandleFunc(getClimateRandom))
r.Get("/climate/{id}", sentryHandler.HandleFunc(getClimate))
port := 7531
fmt.Printf("World Generator API is running on http://localhost:%d.\n", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), r))
}
func SeedFromString(source string) error {
h := md5.New()
_, err := io.WriteString(h, source)
if err != nil {
err = fmt.Errorf("Failed to seed random number generator: %w", err)
return err
}
seed := binary.BigEndian.Uint64(h.Sum(nil))
rand.Seed(int64(seed))
return nil
}
func getClimate(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
var o climate.SimplifiedClimate
err := random.SeedFromString(id)
if err != nil {
handleError(w, r, err)
return
}
randomClimate, err := climate.Random()
if err != nil {
handleError(w, r, err)
return
}
o = randomClimate.Simplify()
json.NewEncoder(w).Encode(o)
}
// Generate generates a climate with a given name
func Generate(name string) (Climate, error) {
rawClimate, err := ByName(name)
if err != nil {
err = fmt.Errorf("Could not generate climate by name: %w", err)
return Climate{}, err
}
climate, err := rawClimate.populate()
if err != nil {
err = fmt.Errorf("Could not generate climate by name: %w", err)
return Climate{}, err
}
return climate, nil
}
func (climate Climate) populate() (Climate, error) {
gems := mineral.Gems()
insects := climate.getFilteredInsects()
metals := mineral.Metals()
stones := mineral.Stones()
trees := climate.getFilteredTrees()
climate.Seasons = climate.getSeasons()
lakeChance := rand.Intn(100)
riverChance := rand.Intn(100)
oceanChance := rand.Intn(100)
wetlandsChance := rand.Intn(100)
if lakeChance > 30 {
climate.HasLakes = true
}
if riverChance > 20 {
climate.HasRivers = true
}
if oceanChance > 80 {
climate.HasOcean = true
}
if wetlandsChance > 80 {
climate.HasWetlands = true
}
soils := climate.getFilteredSoils()
if climate.HasLakes || climate.HasRivers || climate.HasOcean {
climate.Fish = climate.getFish()
} else {
climate.Fish = []fish.Fish{}
}
climate.Insects = insect.RandomSubset(7, insects)
filteredMetals, err := mineral.RandomWeightedSet(climate.MaxMetals, metals)
if err != nil {
err = fmt.Errorf("Could not populate climate: %w", err)
return Climate{}, err
}
climate.Metals = filteredMetals
climate.Gems = mineral.Random(climate.MaxGems, gems)
climate.OtherMinerals = mineral.OtherMinerals()
climate.Animals, err = climate.getAnimals()
if err != nil {
err = fmt.Errorf("Could not populate climate: %w", err)
return Climate{}, err
}
climate.Plants, err = climate.getPlants()
if err != nil {
err = fmt.Errorf("Could not populate climate: %w", err)
return Climate{}, err
}
climate.Soils = soil.Random(climate.MaxSoils, soils)
climate.Stones = mineral.Random(climate.MaxStones, stones)
climate.Trees = tree.RandomSubset(climate.MaxTrees, trees)
resources := climate.getResources()
climate.Resources = resources
description, err := climate.getDescription()
if err != nil {
err = fmt.Errorf("Could not populate climate: %w", err)
return Climate{}, err
}
climate.Description = description
climate.Habitability = climate.calculateHabitability()
return climate, nil
}
Многие функции, такие как doStuff()
, возвращают n случайных элементов из среза с применением некоторой фильтрации.
Все это, я ожидаю, будет согласованным и идентичным, когда один и тот же начальный элемент используется для нескольких прогонов. Однако, это не так. Вместо этого результаты являются случайными каждый раз, независимо от начального значения.
Есть ли какая-то фундаментальная часть операции rand.Intn()
или rand.Seed()
, о которой я не знаю?