/// <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); } }
/// <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); } }