private void Window_Loaded_1(object sender, RoutedEventArgs e) { pop = InitPopulation(); score = new PlantScore(); this.genetic = new BasicEA(pop, score); //this.genetic.Speciation = new ArraySpeciation<DoubleArrayGenome>(); genetic.AddOperation(0.9, new Splice(PlantUniverse.GenomeSize / 3)); genetic.AddOperation(0.1, new MutatePerturb(0.1)); // Display this.universe = new PlantUniverse(); this.universe.Reset(); DoubleArrayGenome bestGenome = (DoubleArrayGenome)genetic.BestGenome; PlantPhysics physics = new PlantPhysics(); PlantGrowth growth = new PlantGrowth(); for (int i = 0; i < 100; i++) { physics.RunPhysics(universe); growth.RunGrowth(universe, bestGenome.Data); } this.display = new DisplayPlant(CanvasOutput); this.display.Universe = this.universe; Thread t = new Thread(DoWork); t.Start(); }
public void DoWork() { var physics = new PlantPhysics(); var growth = new PlantGrowth(); var universe = new PlantUniverse(); universe.Reset(); _display.Universe = universe; for (int i = 0; i < PlantUniverse.EvaluationCycles && !_done; i++) { physics.RunPhysics(universe); growth.RunGrowth(universe, SamplePlant); if (!Dispatcher.CheckAccess()) { Dispatcher.Invoke(() => _display.Paint()); } else { _display.Paint(); } Thread.Sleep(100); } Thread.Sleep(100); }
/** * 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; }
/// <summary> /// Calculate the growth potential for a candidate cell. Evaluates the distance between the candidate cell's info /// vector and the two growth vectors in the genome. The minimum of these two vectors will be returned if /// it is below a specified minimum threshold. /// </summary> /// <param name="universe">The universe to evaluate.</param> /// <param name="row">The row to evaluate.</param> /// <param name="col">The column to evaluate.</param> /// <param name="genome">The genome.</param> /// <returns>The minimum distance.</returns> private double GetGrowthPotential(PlantUniverse universe, int row, int col, double[] genome) { double[] cellVec = universe.GetCellInfoVector(row, col); double d1 = _dist.Calculate(cellVec, 0, genome, PlantUniverse.CellVectorLength * 2, PlantUniverse.CellVectorLength); double d2 = _dist.Calculate(cellVec, 0, genome, PlantUniverse.CellVectorLength * 3, PlantUniverse.CellVectorLength); double result = Math.Min(d1, d2); if (result > PlantUniverse.MinGrowthDist) { result = -1; } return(result); }
/// <summary> /// Evaluate neighbors to see where to grow into. /// </summary> /// <param name="universe">The universe.</param> /// <param name="row">The row.</param> /// <param name="col">The column.</param> /// <param name="genome">The genome.</param> /// <param name="allowRoot">Are roots allowed?</param> /// <param name="allowSurface">Is surface growth allowed.</param> private void EvaluateNeighbors(PlantUniverse universe, int row, int col, double[] genome, bool allowRoot, bool allowSurface) { int growthTargetRow = row; int growthTargetCol = col; double growthTargetScore = double.PositiveInfinity; for (int i = 0; i < _colTransform.Length; i++) { int evalCol = col + _colTransform[i]; int evalRow = row + _rowTransform[i]; if (!allowRoot && evalRow >= PlantUniverse.GroundLine) { continue; } if (!allowSurface && evalRow < PlantUniverse.GroundLine) { continue; } if (universe.IsValid(evalRow, evalCol)) { double p = GetGrowthPotential(universe, evalRow, evalCol, genome); if (p > 0) { if (p < growthTargetScore) { growthTargetScore = p; growthTargetRow = evalRow; growthTargetCol = evalCol; } } } } // Grow new cell, if requested, did we ever set target row & col to anything? if (growthTargetRow != row || growthTargetCol != col) { _newComposition[growthTargetRow][growthTargetCol] = true; } }
/// <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; } } }
public void RunPhysics(PlantUniverse universe) { DistributeEnergy(universe); DistributeNourishment(universe); }
/// <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; } } } }