/** * Distribute nourishment in the universe. * * @param universe The universe. */ private void DistributeNourishment(PlantUniverse universe) { double rootCount = 0; double surfaceCount = 0; // Distribute sun energy downward var waterTable = new double[PlantUniverse.UniverseWidth]; for (int i = 0; i < waterTable.Length; i++) { waterTable[i] = 1.0; } for (int row = PlantUniverse.UniverseHeight - 1; row >= 0; row--) { for (int col = 0; col < PlantUniverse.UniverseWidth; col++) { double decay; // no water above ground decay = row < PlantUniverse.GroundLine ? 0 : 1; PlantUniverseCell cell = universe.GetCell(row, col); cell.CalculatedWater = waterTable[col]; // Collect resources for live cells if (cell.IsAlive) { // Live cells cause the water to decay (roots collect) decay *= PlantUniverse.Decay; // Set the energy based on sunlight level and composition of the live cell double myWater = cell.CalculatedWater * cell.Leafyness; double transWater = universe.CalculateTransferNourishment(row, col) * (1.0 - cell.Leafyness); double n = Math.Max(myWater, transWater); n = Math.Max(PlantUniverse.MinLivingEnergy, n); cell.Nourishment = n; // update the root and surface counts if (row >= PlantUniverse.GroundLine) { rootCount += cell.Nourishment; } else { surfaceCount += cell.Leafyness; } } waterTable[col] *= decay; } } universe.RootCount = rootCount; universe.SurfaceCount = surfaceCount; }
/// <inheritdoc /> public double CalculateScore(IMLMethod algo) { var genome = (DoubleArrayGenome)algo; var universe = new PlantUniverse(); universe.Reset(); var physics = new PlantPhysics(); var growth = new PlantGrowth(); // Run the generations. for (int i = 0; i < PlantUniverse.EvaluationCycles; i++) { physics.RunPhysics(universe); growth.RunGrowth(universe, genome.Data); } // Count the amount of green. int count = 0; double sum = 0; for (int row = 0; row < PlantUniverse.UniverseHeight; row++) { for (int col = 0; col < PlantUniverse.UniverseWidth; col++) { PlantUniverseCell cell = universe.GetCell(row, col); if (cell.IsAlive) { if (row >= PlantUniverse.GroundLine) { sum += 0.5; } else { sum += cell.Leafyness; } } count++; } } return(sum / count); }
/** * Distribute the sunlight energy in the universe. * * @param universe The universe. */ private void DistributeEnergy(PlantUniverse universe) { // Distribute sun energy downward var sunlight = new double[PlantUniverse.UniverseWidth]; for (int i = 0; i < sunlight.Length; i++) { sunlight[i] = 1.0; } for (int row = 0; row < PlantUniverse.UniverseHeight; row++) { for (int col = 0; col < PlantUniverse.UniverseWidth; col++) { // no sun underground double decay = row >= PlantUniverse.GroundLine ? 0 : 1; PlantUniverseCell cell = universe.GetCell(row, col); cell.CalculatedSunlight = sunlight[col]; // Collect resources for live cells if (cell.IsAlive) { // Live cells cause the sunlight to decay (shade) decay *= PlantUniverse.Decay * cell.Leafyness; // Set the energy based on sunlight level and composition of the live cell double myEnergy = cell.CalculatedSunlight * cell.Leafyness; double transEnergy = universe.CalculateTransferEnergy(row, col) * (1.0 - cell.Leafyness); double e = Math.Max(myEnergy, transEnergy); e = Math.Max(PlantUniverse.MinLivingEnergy, e); cell.Energy = e; } sunlight[col] *= decay; } } }
/// <summary> /// Run a growth cycle for the universe. /// </summary> /// <param name="universe">The universe.</param> /// <param name="genome">The genome.</param> public void RunGrowth(PlantUniverse universe, double[] genome) { // Does this plant have enough roots to grow? if (universe.SurfaceCount < AIFH.DefaultPrecision) { return; } // The amount of leafy material per root nourishment. A higher number indicates // more root nourishment than leafs. double rootRatio = universe.RootCount / universe.SurfaceCount; bool allowRoot = rootRatio < 0.5; //rootRatio < 0.1; bool allowSurface = rootRatio > 0.5; // Reset the new composition to be the composition of the current universe for (int row = 0; row < PlantUniverse.UniverseHeight; row++) { for (int col = 0; col < PlantUniverse.UniverseWidth; col++) { _newComposition[row][col] = false; } } for (int row = 0; row < PlantUniverse.UniverseHeight; row++) { for (int col = 0; col < PlantUniverse.UniverseWidth; col++) { PlantUniverseCell cell = universe.GetCell(row, col); // see if we want to change the composition if (row < PlantUniverse.GroundLine) { double[] cellVec = universe.GetCellInfoVector(row, col); double d1 = _dist.Calculate(cellVec, 0, genome, 0, PlantUniverse.CellVectorLength); double d2 = _dist.Calculate(cellVec, 0, genome, PlantUniverse.CellVectorLength, PlantUniverse.CellVectorLength); if (d1 < d2) { cell.Leafyness = (cell.Leafyness * PlantUniverse.StemTransition); } } // Evaluate growth into each neighbor cell if (universe.CanGrow(row, col)) { EvaluateNeighbors(universe, row, col, genome, allowRoot, allowSurface); } } } // Copy the new composition back to the universe for (int row = 0; row < PlantUniverse.UniverseHeight; row++) { for (int col = 0; col < PlantUniverse.UniverseWidth; col++) { PlantUniverseCell cell = universe.GetCell(row, col); if (_newComposition[row][col]) { cell.Leafyness = row >= PlantUniverse.GroundLine ? 0 : 1.0; cell.Energy = 1.0; cell.Nourishment = 1.0; } } } }