/// <summary> /// The heart of the simulation that handles the processed parameters and calculates future populations. /// </summary> private static void SimulatePatchStep(RunResults populations, Patch patch, List <Species> species, Random random) { // Skip if there aren't any species in this patch if (species.Count < 1) { return; } var biome = patch.Biome; // TODO: this is where the proper auto-evo algorithm goes // Here's a temporary boost when there are few species and penalty // when there are many species bool lowSpecies = species.Count <= Constants.AUTO_EVO_LOW_SPECIES_THRESHOLD; bool highSpecies = species.Count >= Constants.AUTO_EVO_HIGH_SPECIES_THRESHOLD; foreach (var currentSpecies in species) { int currentPopulation = populations.GetPopulationInPatch(currentSpecies, patch); int populationChange = random.Next( -Constants.AUTO_EVO_RANDOM_POPULATION_CHANGE, Constants.AUTO_EVO_RANDOM_POPULATION_CHANGE + 1); if (lowSpecies) { populationChange += Constants.AUTO_EVO_LOW_SPECIES_BOOST; } else if (highSpecies) { populationChange -= Constants.AUTO_EVO_HIGH_SPECIES_PENALTY; } populations.AddPopulationResultForSpecies(currentSpecies, patch, currentPopulation + populationChange); } }
private void CheckCurrentPatchSpecies(RunResults results) { foreach (var candidateSpecies in patch.SpeciesInPatch) { if (candidateSpecies.Value < configuration.NewBiodiversityIncreasingSpeciesPopulation) { continue; } var found = TryBiodiversitySplit(candidateSpecies.Key, true); if (found == null) { continue; } OnSpeciesCreated(found, candidateSpecies.Key, results); if (configuration.UseBiodiversityForceSplit) { // TODO: implement this throw new NotImplementedException( "Marking biodiversity increase as split is not implemented"); } break; } }
public bool RunStep(RunResults results) { // ReSharper disable RedundantArgumentDefaultValue var config = new SimulationConfiguration(configuration, map, 1) { Results = results, CollectEnergyInformation = collectEnergyInfo, }; // ReSharper restore RedundantArgumentDefaultValue if (extraSpecies != null) { config.ExtraSpecies = extraSpecies; } if (excludedSpecies != null) { config.ExcludedSpecies = excludedSpecies; } // Directly feed the population results to the main results object PopulationSimulation.Simulate(config); return(true); }
public bool RunStep(RunResults results) { // We gather populations that may be targeted in the patch, depending on the parameters, // this may exclude migrated or newly created species. // Excluded species are only protected for one generation. The player is a target as well, // although they will be rescued before extinction can apply to them. var targetSpeciesPopulationsByPatch = results.GetPopulationsByPatch( !configuration.ProtectMigrationsFromSpeciesCap, true); var newSpecies = results.GetNewSpecies(); foreach (var patch in patches) { // If no species exist in a patch, we need to skip handling the current patch if (!targetSpeciesPopulationsByPatch.TryGetValue(patch, out var tmpTarget)) { continue; } IEnumerable <KeyValuePair <Species, long> > targetEnumerator = tmpTarget; if (configuration.ProtectNewCellsFromSpeciesCap) { targetEnumerator = targetEnumerator.Where(s => !newSpecies.Contains(s.Key)); } var targetSpecies = targetEnumerator.ToList(); // Only bother if we're above the limit if (targetSpecies.Count <= configuration.MaximumSpeciesInPatch) { continue; } GD.Print("Running extinction step in patch ", patch.Name, ". ", "Total count:", targetSpecies.Count); var orderedTargetSpecies = targetSpecies.OrderBy(s => s.Value).Select(s => s.Key); var speciesToRemoveCount = targetSpecies.Count - Math.Max(configuration.MaximumSpeciesInPatch, 0); // Remove worst-faring species in targets (which again exclude *temporarily* protected ones). foreach (var speciesToRemove in orderedTargetSpecies.Take(speciesToRemoveCount)) { // We rescue the player if needed if (speciesToRemove.PlayerSpecies) { continue; } GD.Print("Forced extinction of species ", speciesToRemove.FormattedName, " in patch ", patch.Name, "."); results.KillSpeciesInPatch(speciesToRemove, patch, configuration.RefundMigrationsInExtinctions); } } return(true); }
public bool RunStep(RunResults results) { foreach (var species in speciesToCheck) { results.RemoveMigrationsForSplitPatches(species); } return(true); }
protected override void OnBestResultFound(RunResults results, IAttemptResult bestVariant) { var variant = (AttemptResult)bestVariant; if (variant.Migration == null) { return; } results.AddMigrationResultForSpecies(species, variant.Migration); }
private void OnSpeciesCreated(Species species, Species fromSpecies, RunResults results) { results.AddNewSpecies(species, new[] { new KeyValuePair <Patch, long>(patch, configuration.NewBiodiversityIncreasingSpeciesPopulation), }, RunResults.NewSpeciesType.FillNiche, fromSpecies); createdASpecies = true; }
public bool RunStep(RunResults results) { if (tryCurrentPatch) { CheckCurrentPatchSpecies(results); tryCurrentPatch = false; return(false); } if (createdASpecies) { return(true); } CheckNeighbourPatchSpecies(results); return(true); }
private void CheckNeighbourPatchSpecies(RunResults results) { var alreadyCheckedSpecies = new HashSet <Species>(patch.SpeciesInPatch.Select(p => p.Key)); foreach (var neighbour in patch.Adjacent) { foreach (var candidateSpecies in neighbour.SpeciesInPatch) { if (candidateSpecies.Value < configuration.NewBiodiversityIncreasingSpeciesPopulation || alreadyCheckedSpecies.Contains(candidateSpecies.Key)) { continue; } if (random.NextDouble() > configuration.BiodiversityFromNeighbourPatchChance) { continue; } alreadyCheckedSpecies.Add(candidateSpecies.Key); var found = TryBiodiversitySplit(candidateSpecies.Key, false); if (found == null) { continue; } OnSpeciesCreated(found, candidateSpecies.Key, results); if (!configuration.BiodiversityNearbyPatchIsFreePopulation) { // TODO: implement this throw new NotImplementedException( "adding population penalty to neighbour patch is not implemented"); } break; } } }
public bool Step(RunResults results) { bool ran = false; if (tryCurrentVariant) { var result = TryCurrentVariant(); if (currentBest == null || result.Score > currentBest.Score) { currentBest = result; } tryCurrentVariant = false; ran = true; } if (variantsToTry > 0 && !ran) { var result = TryVariant(); if (currentBest == null || result.Score > currentBest.Score) { currentBest = result; } --variantsToTry; ran = true; } if (!tryCurrentVariant && variantsToTry <= 0) { // Store the best result OnBestResultFound(results, currentBest); return(true); } else { return(false); } }
public bool RunStep(RunResults results) { bool ran = false; if (tryCurrentVariant) { var result = TryCurrentVariant(); CheckScore(result); tryCurrentVariant = false; ran = true; } if (variantsToTry > 0 && !ran) { var result = TryVariant(); CheckScore(result); --variantsToTry; } if (!tryCurrentVariant && variantsToTry <= 0) { // Store the best result if (currentBest == null) { throw new Exception($"Variant step didn't try anything ({nameof(currentBest)} is null)"); } OnBestResultFound(results, currentBest); return(true); } return(false); }
public bool RunStep(RunResults results) { operation(results); return(true); }
/// <summary> /// Called after the best attempted variant is determined /// </summary> /// <param name="results">Results to apply the found solution to.</param> /// <param name="bestVariant">Best variant found.</param> protected abstract void OnBestResultFound(RunResults results, IAttemptResult bestVariant);
/// <summary> /// The heart of the simulation that handles the processed parameters and calculates future populations. /// </summary> private static void SimulatePatchStep(RunResults populations, Patch patch, List <Species> genericSpecies, Random random) { _ = random; // Skip if there aren't any species in this patch if (genericSpecies.Count < 1) { return; } // This algorithm version is for microbe species var species = genericSpecies.Select(s => (MicrobeSpecies)s).ToList(); var biome = patch.Biome; var sunlightInPatch = biome.Compounds[Sunlight].Dissolved * Constants.AUTO_EVO_SUNLIGHT_ENERGY_AMOUNT; var hydrogenSulfideInPatch = biome.Compounds[HydrogenSulfide].Density * biome.Compounds[HydrogenSulfide].Amount * Constants.AUTO_EVO_COMPOUND_ENERGY_AMOUNT; var glucoseInPatch = (biome.Compounds[Glucose].Density * biome.Compounds[Glucose].Amount + patch.GetTotalChunkCompoundAmount(Glucose)) * Constants.AUTO_EVO_COMPOUND_ENERGY_AMOUNT; var ironInPatch = patch.GetTotalChunkCompoundAmount(Iron) * Constants.AUTO_EVO_COMPOUND_ENERGY_AMOUNT; // Begin of new auto-evo prototype algorithm var speciesEnergies = new Dictionary <MicrobeSpecies, float>(species.Count); var totalPhotosynthesisScore = 0.0f; var totalChemosynthesisScore = 0.0f; var totalChemolithoautotrophyScore = 0.0f; var totalGlucoseScore = 0.0f; var totalPredationScore = 0.0f; // Calculate the total scores of each type in the current patch foreach (var currentSpecies in species) { totalPhotosynthesisScore += GetCompoundUseScore(currentSpecies, Sunlight); totalChemosynthesisScore += GetCompoundUseScore(currentSpecies, HydrogenSulfide); totalChemolithoautotrophyScore += GetCompoundUseScore(currentSpecies, Iron); totalGlucoseScore += GetCompoundUseScore(currentSpecies, Glucose); totalPredationScore += GetPredationScore(currentSpecies); } // Avoid division by 0 totalPhotosynthesisScore = Math.Max(MathUtils.EPSILON, totalPhotosynthesisScore); totalChemosynthesisScore = Math.Max(MathUtils.EPSILON, totalChemosynthesisScore); totalChemolithoautotrophyScore = Math.Max(MathUtils.EPSILON, totalChemolithoautotrophyScore); totalGlucoseScore = Math.Max(MathUtils.EPSILON, totalGlucoseScore); totalPredationScore = Math.Max(MathUtils.EPSILON, totalPredationScore); // Calculate the share of environmental energy captured by each species var energyAvailableForPredation = 0.0f; foreach (var currentSpecies in species) { var currentSpeciesEnergy = 0.0f; currentSpeciesEnergy += sunlightInPatch * GetCompoundUseScore(currentSpecies, Sunlight) / totalPhotosynthesisScore; currentSpeciesEnergy += hydrogenSulfideInPatch * GetCompoundUseScore(currentSpecies, HydrogenSulfide) / totalChemosynthesisScore; currentSpeciesEnergy += ironInPatch * GetCompoundUseScore(currentSpecies, Iron) / totalChemolithoautotrophyScore; currentSpeciesEnergy += glucoseInPatch * GetCompoundUseScore(currentSpecies, Glucose) / totalGlucoseScore; energyAvailableForPredation += currentSpeciesEnergy * Constants.AUTO_EVO_PREDATION_ENERGY_MULTIPLIER; speciesEnergies.Add(currentSpecies, currentSpeciesEnergy); } // Calculate the share of predation done by each species // Then update populations foreach (var currentSpecies in species) { speciesEnergies[currentSpecies] += energyAvailableForPredation * GetPredationScore(currentSpecies) / totalPredationScore; speciesEnergies[currentSpecies] -= energyAvailableForPredation / species.Count; var newPopulation = (long)(speciesEnergies[currentSpecies] / Math.Pow(currentSpecies.Organelles.Count, 1.3f)); // Can't survive without enough population if (newPopulation < Constants.AUTO_EVO_MINIMUM_VIABLE_POPULATION) { newPopulation = 0; } populations.AddPopulationResultForSpecies(currentSpecies, patch, newPopulation); } }
protected override void OnBestResultFound(RunResults results, IAttemptResult bestVariant) { results.AddMutationResultForSpecies(species, ((AttemptResult)bestVariant).Mutation); }