private bool TryLayoutNode(TLayout layout, TNode node, out TLayout newLayout) { // possibleShapes.Shuffle(Random); var neighbouringConfigurations = GetNeighbouringConfigurations(layout, node); var possibleShapes = LayoutOperations.GetShapesForNode(node); var notUsedShapes = possibleShapes.Where(x => neighbouringConfigurations.All(y => !y.ShapeContainer.Equals(x))).ToList(); if (notUsedShapes.Count != 0) { possibleShapes = notUsedShapes; } for (int i = 0; i < NumberOfAttemptsPerNode; i++) { var shape = possibleShapes.GetRandom(Random); var position = LayoutOperations.GetRandomPosition(shape, neighbouringConfigurations); var isValid = LayoutOperations.IsValid(layout, node, shape, position); // TODO: this is not really needed newLayout = layout.SmartClone(); newLayout.SetConfiguration(node, CreateConfiguration(shape, position)); OnPerturbed?.Invoke(newLayout); if (isValid) { return(true); } } newLayout = default; return(false); }
public IEnumerable <TLayout> Evolve(TLayout initialLayout, Chain <TNode> chain, int count) { for (int i = 0; i < count; i++) { var copy = initialLayout.SmartClone(); layoutOperations.AddChain(copy, chain.Nodes, true, out var iterationsCount); foreach (var _ in chain.Nodes) { OnPerturbed?.Invoke(this, copy); } if (layoutOperations.IsLayoutValid(copy)) { // TODO: why chain.Nodes instead of chain? if (layoutOperations.TryCompleteChain(copy, chain.Nodes)) { yield return(copy); } } } }
private void SetupGenerator() { var mapping = mapDescription.GetMapping(); var chainsGeneric = configuration.Chains; if (chainsGeneric == null) { var chainDecomposition = new TwoStageChainDecomposition <TNode>(mapDescriptionOriginal, new BreadthFirstChainDecomposition <TNode>(configuration.ChainDecompositionConfiguration ?? new ChainDecompositionConfiguration())); chainsGeneric = chainDecomposition.GetChains(mapDescriptionOriginal.GetGraph()); } var chains = chainsGeneric .Select(x => new Chain <int>(x.Nodes.Select(y => mapping[y]).ToList(), x.Number)) .ToList(); var generatorPlanner = new GeneratorPlanner <Layout <Configuration <CorridorsData> >, int>(configuration.SimulatedAnnealingMaxBranching); var configurationSpacesGenerator = new ConfigurationSpacesGenerator( new PolygonOverlap(), DoorHandler.DefaultHandler, new OrthogonalLineIntersection(), new GridPolygonUtils()); var configurationSpaces = configurationSpacesGenerator.GetConfigurationSpaces <Configuration <CorridorsData> >(mapDescription); //var corridorConfigurationSpaces = mapDescription.IsWithCorridors ? configurationSpacesGenerator.Generate<TNode, Configuration<CorridorsData>>(mapDescription, mapDescription.CorridorsOffsets) : configurationSpaces; var corridorConfigurationSpaces = configurationSpaces; var averageSize = configurationSpaces.GetAverageSize(); var polygonOverlap = new FastPolygonOverlap(); var stageOneConstraints = new List <INodeConstraint <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>, CorridorsData> > { new BasicConstraint <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>, CorridorsData, IntAlias <PolygonGrid2D> >( new FastPolygonOverlap(), averageSize, configurationSpaces ), new CorridorConstraints <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>, CorridorsData, IntAlias <PolygonGrid2D> >( mapDescription, averageSize, corridorConfigurationSpaces ), }; if (!configuration.RoomsCanTouch) { stageOneConstraints.Add(new TouchingConstraints <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>, CorridorsData, IntAlias <PolygonGrid2D> >( mapDescription, polygonOverlap )); } var stageOneConstraintsEvaluator = new ConstraintsEvaluator <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>, IntAlias <PolygonGrid2D>, CorridorsData>(stageOneConstraints); //if (mapDescription.IsWithCorridors) //{ // layoutOperations.AddNodeConstraint(new CorridorConstraints<Layout<Configuration<CorridorsData>>, int, Configuration<CorridorsData>, CorridorsData, IntAlias<GridPolygon>>( // mapDescription, // averageSize, // corridorConfigurationSpaces // )); // if (!false) // TODO: // { // var polygonOverlap = new FastPolygonOverlap(); // layoutOperations.AddNodeConstraint(new TouchingConstraints<Layout<Configuration<CorridorsData>>, int, Configuration<CorridorsData>, CorridorsData, IntAlias<GridPolygon>>( // mapDescription, // polygonOverlap // )); // } //} var roomShapesHandler = new RoomShapesHandler <int, Configuration <CorridorsData> >( configurationSpaces, configurationSpaces.GetIntAliasMapping(), mapDescription, configuration.RepeatModeOverride ); var layoutOperations = new LayoutOperations <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData>, IntAlias <PolygonGrid2D>, CorridorsData>(corridorConfigurationSpaces, configurationSpaces.GetAverageSize(), mapDescription, stageOneConstraintsEvaluator, stageOneConstraintsEvaluator, roomShapesHandler, configuration.ThrowIfRepeatModeNotSatisfied); var initialLayout = new Layout <Configuration <CorridorsData> >(mapDescription.GetGraph()); var layoutConverter = new BasicLayoutConverter <Layout <Configuration <CorridorsData> >, TNode, Configuration <CorridorsData> >(mapDescription, configurationSpaces, configurationSpaces.GetIntAliasMapping()); var layoutEvolver = new PlatformersEvolver <Layout <Configuration <CorridorsData> >, int, Configuration <CorridorsData> >(layoutOperations); generator = new ChainBasedGenerator <Layout <Configuration <CorridorsData> >, MapLayout <TNode>, int>(initialLayout, generatorPlanner, chains, layoutEvolver, layoutConverter); generator.OnRandomInjected += (random) => { ((IRandomInjectable)configurationSpaces).InjectRandomGenerator(random); ((IRandomInjectable)layoutOperations).InjectRandomGenerator(random); ((IRandomInjectable)layoutEvolver).InjectRandomGenerator(random); ((IRandomInjectable)layoutConverter).InjectRandomGenerator(random); }; generator.OnCancellationTokenInjected += (token) => { ((ICancellable)generatorPlanner).SetCancellationToken(token); ((ICancellable)layoutEvolver).SetCancellationToken(token); }; // layoutEvolver.OnEvent += (sender, args) => OnSimulatedAnnealingEvent?.Invoke(sender, args); layoutEvolver.OnPerturbed += (sender, layout) => OnPerturbed?.Invoke(layoutConverter.Convert(layout, false)); layoutEvolver.OnPerturbed += (sender, layout) => OnPerturbedInternal?.Invoke(layout); layoutEvolver.OnValid += (sender, layout) => OnPartialValid?.Invoke(layoutConverter.Convert(layout, true)); generatorPlanner.OnLayoutGenerated += layout => OnValid?.Invoke(layoutConverter.Convert(layout, true)); }
/// <inheritdoc /> public IEnumerable <TLayout> Evolve(TLayout initialLayout, Chain <TNode> chain, int count) { var configuration = GetConfiguration(chain.Number); if (!chain.IsFromFace && configuration.HandleTreesGreedily) { var iters = 0; var lastEventIters = 0; for (int i = 0; i < 2; i++) { if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } for (int k = 0; k < 1; k++) { if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } var copy = initialLayout.SmartClone(); LayoutOperations.AddChain(copy, chain.Nodes, true, out var addChainIterationsCount); iters += addChainIterationsCount; // An event must be sent in order for the early stopping handler to work OnPerturbed?.Invoke(this, copy); if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } if (LayoutOperations.IsLayoutValid(copy)) { if (LayoutOperations.TryCompleteChain(copy, chain.Nodes)) { OnPerturbed?.Invoke(this, copy); if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.LayoutGenerated, IterationsSinceLastEvent = iters - lastEventIters, IterationsTotal = iters, LayoutsGenerated = -1, ChainNumber = chain.Number, }); lastEventIters = iters; yield return(copy); break; } } OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.OutOfIterations, IterationsSinceLastEvent = iters - lastEventIters, IterationsTotal = iters, LayoutsGenerated = -1, ChainNumber = chain.Number, }); lastEventIters = iters; } } yield break; } if (addNodesGreedilyBeforeEvolve) { LayoutOperations.AddChain(initialLayout, chain.Nodes, true, out var addChainIterationsCount); } const double p0 = 0.2d; const double p1 = 0.01d; var t0 = -1d / Math.Log(p0); var t1 = -1d / Math.Log(p1); var ratio = Math.Pow(t1 / t0, 1d / (configuration.Cycles - 1)); var deltaEAvg = 0d; var acceptedSolutions = 1; var t = t0; var layouts = new List <TLayout>(); var originalLayout = initialLayout; var currentLayout = originalLayout; #region Debug output //if (withDebugOutput) //{ // Console.WriteLine($"Initial energy: {layoutOperations.GetEnergy(currentLayout)}"); //} #endregion var numberOfFailures = 0; var stageTwoFailures = 0; var iterations = 0; var lastEventIterations = 0; var shouldStop = false; for (var i = 0; i < configuration.Cycles; i++) { var wasAccepted = false; #region Random restarts if (enableRandomRestarts) { if (ShouldRestart(numberOfFailures)) { OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.RandomRestart, IterationsSinceLastEvent = iterations - lastEventIterations, IterationsTotal = iterations, LayoutsGenerated = layouts.Count, ChainNumber = chain.Number, }); yield break; } } #endregion if (iterations - lastEventIterations > configuration.MaxIterationsWithoutSuccess) { break; } if (shouldStop) { break; } for (var j = 0; j < configuration.TrialsPerCycle; j++) { if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } if (stageTwoFailures > configuration.MaxStageTwoFailures) { shouldStop = true; break; } iterations++; var perturbedLayout = PerturbLayout(currentLayout, chain.Nodes, out var energyDelta); OnPerturbed?.Invoke(this, perturbedLayout); // TODO: can we check the energy instead? if (LayoutOperations.IsLayoutValid(perturbedLayout, chain.Nodes)) { #region Random restarts if (enableRandomRestarts && randomRestartsSuccessPlace == RestartSuccessPlace.OnValid) { wasAccepted = true; if (randomRestartsResetCounter) { numberOfFailures = 0; } } #endregion // TODO: wouldn't it be too slow to compare againts all? if (IsDifferentEnough(perturbedLayout, layouts)) { // TODO 2SG: should we clone before TryCompleteChain or should TryCompleteChain not change the layout? var newLayout = perturbedLayout.SmartClone(); var shouldContinue = LayoutOperations.TryCompleteChain(newLayout, chain.Nodes); if (shouldContinue) { layouts.Add(newLayout); OnValid?.Invoke(this, newLayout); #region Random restarts if (enableRandomRestarts && randomRestartsSuccessPlace == RestartSuccessPlace.OnValidAndDifferent) { wasAccepted = true; if (randomRestartsResetCounter) { numberOfFailures = 0; } } #endregion OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.LayoutGenerated, IterationsSinceLastEvent = iterations - lastEventIterations, IterationsTotal = iterations, LayoutsGenerated = layouts.Count, ChainNumber = chain.Number, }); yield return(newLayout); lastEventIterations = iterations; stageTwoFailures = 0; #region Debug output //if (withDebugOutput) //{ // Console.WriteLine($"Found layout, cycle {i}, trial {j}, energy {layoutOperations.GetEnergy(perturbedLayout)}"); //} #endregion if (layouts.Count >= count) { #region Debug output //if (withDebugOutput) //{ // Console.WriteLine($"Returning {layouts.Count} partial layouts"); //} #endregion yield break; } } else { stageTwoFailures++; OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.StageTwoFailure, IterationsSinceLastEvent = iterations - lastEventIterations, IterationsTotal = iterations, LayoutsGenerated = layouts.Count, ChainNumber = chain.Number, ResetsIterationsSinceLastEvent = false, }); } } } var deltaAbs = Math.Abs(energyDelta); var accept = false; if (energyDelta > 0) { if (i == 0 && j == 0) { deltaEAvg = deltaAbs * 15; } var p = Math.Pow(Math.E, -deltaAbs / (deltaEAvg * t)); if (Random.NextDouble() < p) { accept = true; } } else { accept = true; } if (accept) { acceptedSolutions++; currentLayout = perturbedLayout; deltaEAvg = (deltaEAvg * (acceptedSolutions - 1) + deltaAbs) / acceptedSolutions; #region Random restarts if (enableRandomRestarts && randomRestartsSuccessPlace == RestartSuccessPlace.OnAccepted) { wasAccepted = true; if (randomRestartsResetCounter) { numberOfFailures = 0; } } #endregion } } if (!wasAccepted) { numberOfFailures++; } t = t * ratio; } OnEvent?.Invoke(this, new SimulatedAnnealingEventArgs() { Type = SimulatedAnnealingEventType.OutOfIterations, IterationsSinceLastEvent = iterations - lastEventIterations, IterationsTotal = iterations, LayoutsGenerated = layouts.Count, ChainNumber = chain.Number, }); }
private List <Layout> GetExtendedLayouts(Layout layout, List <int> chain, bool lastChain) { var cycles = 50; var trialsPerCycle = 500; var p0 = 0.2d; var p1 = 0.01d; var t0 = -1d / Math.Log(p0); var t1 = -1d / Math.Log(p1); var ratio = Math.Pow(t1 / t0, 1d / (cycles - 1)); var deltaEAvg = 0d; var acceptedSolutions = 1; var t = t0; var layouts = new List <Layout>(); var originalLayout = layout; //AddChainToLayout(layout, chain); var currentLayout = originalLayout; if (WithDebug) { Console.WriteLine($"Initial energy: {currentLayout.GetEnergy()}"); } var numFailures = 0; for (var i = 0; i < cycles; i++) { var wasAccepted = false; if (numFailures > 8 && Random.Next(0, 2) == 0) { if (WithDebug) { Console.WriteLine($"Break, we got {numFailures} failures"); } break; } if (numFailures > 6 && Random.Next(0, 3) == 0) { if (WithDebug) { Console.WriteLine($"Break, we got {numFailures} failures"); } break; } if (numFailures > 4 && Random.Next(0, 5) == 0) { if (WithDebug) { Console.WriteLine($"Break, we got {numFailures} failures"); } break; } if (numFailures > 2 && Random.Next(0, 7) == 0) { if (WithDebug) { Console.WriteLine($"Break, we got {numFailures} failures"); } break; } for (var j = 0; j < trialsPerCycle; j++) { iterationsCount++; var perturbedLayout = PerturbLayout(currentLayout, chain, out var energyDelta); // TODO: locally perturb the layout OnPerturbed?.Invoke((ILayout <TNode, TPolygon, TPosition, IntLine>)perturbedLayout); // TODO: should probably check only the perturbed node - other nodes did not change if (IsLayoutValid(perturbedLayout)) { OnValid?.Invoke((ILayout <TNode, TPolygon, TPosition, IntLine>)perturbedLayout); // TODO: wouldn't it be too slow to compare againts all? if (layouts.TrueForAll(x => x.GetDifference(perturbedLayout, chain) > 2 * MinimumDifference)) { wasAccepted = true; AddDoors(new List <Layout>() { perturbedLayout }); layouts.Add(perturbedLayout); OnValidAndDifferent?.Invoke((ILayout <TNode, TPolygon, TPosition, IntLine>)perturbedLayout); if (WithDebug) { Console.WriteLine($"Found layout, cycle {i}, trial {j}, energy {perturbedLayout.GetEnergy()}"); } if (layouts.Count >= 15) { if (WithDebug) { Console.WriteLine($"Returning {layouts.Count} partial layouts"); } return(layouts); } } } var deltaAbs = Math.Abs(energyDelta); var accept = false; if (energyDelta > 0) { if (i == 0 && j == 0) { deltaEAvg = deltaAbs * 15; } var p = Math.Pow(Math.E, -deltaAbs / (deltaEAvg * t)); if (Random.NextDouble() < p) { accept = true; } } else { accept = true; } if (accept) { acceptedSolutions++; currentLayout = perturbedLayout; deltaEAvg = (deltaEAvg * (acceptedSolutions - 1) + deltaAbs) / acceptedSolutions; } } if (!wasAccepted) { numFailures++; } t = t * ratio; } if (WithDebug) { Console.WriteLine($"Returning {layouts.Count} partial layouts"); } return(layouts); }
/// <inheritdoc /> public IEnumerable <TLayout> Evolve(TLayout initialLayout, IList <TNode> chain, int count) { const double p0 = 0.2d; const double p1 = 0.01d; var t0 = -1d / Math.Log(p0); var t1 = -1d / Math.Log(p1); var ratio = Math.Pow(t1 / t0, 1d / (Cycles - 1)); var deltaEAvg = 0d; var acceptedSolutions = 1; var t = t0; var layouts = new List <TLayout>(); var originalLayout = initialLayout; var currentLayout = originalLayout; #region Debug output //if (withDebugOutput) //{ // Console.WriteLine($"Initial energy: {layoutOperations.GetEnergy(currentLayout)}"); //} #endregion var numberOfFailures = 0; for (var i = 0; i < Cycles; i++) { var wasAccepted = false; #region Random restarts if (enableRandomRestarts) { if (ShouldRestart(numberOfFailures)) { break; } } #endregion for (var j = 0; j < TrialsPerCycle; j++) { if (CancellationToken.HasValue && CancellationToken.Value.IsCancellationRequested) { yield break; } var perturbedLayout = PerturbLayout(currentLayout, chain, out var energyDelta); OnPerturbed?.Invoke(perturbedLayout); // TODO: can we check the energy instead? if (LayoutOperations.IsLayoutValid(perturbedLayout, chain)) { #region Random restarts if (enableRandomRestarts && randomRestartsSuccessPlace == RestartSuccessPlace.OnValid) { wasAccepted = true; if (randomRestartsResetCounter) { numberOfFailures = 0; } } #endregion // TODO: wouldn't it be too slow to compare againts all? if (IsDifferentEnough(perturbedLayout, layouts)) { var shouldContinue = true; // TODO: should it be like this? if (LayoutOperations is ILayoutOperationsWithCorridors <TLayout, TNode> layoutOperationsWithCorridors) { shouldContinue = layoutOperationsWithCorridors.AddCorridors(perturbedLayout, chain); } if (shouldContinue) { layouts.Add(perturbedLayout); OnValid?.Invoke(perturbedLayout); #region Random restarts if (enableRandomRestarts && randomRestartsSuccessPlace == RestartSuccessPlace.OnValidAndDifferent) { wasAccepted = true; if (randomRestartsResetCounter) { numberOfFailures = 0; } } #endregion yield return(perturbedLayout); #region Debug output //if (withDebugOutput) //{ // Console.WriteLine($"Found layout, cycle {i}, trial {j}, energy {layoutOperations.GetEnergy(perturbedLayout)}"); //} #endregion if (layouts.Count >= count) { #region Debug output //if (withDebugOutput) //{ // Console.WriteLine($"Returning {layouts.Count} partial layouts"); //} #endregion yield break; } } } } var deltaAbs = Math.Abs(energyDelta); var accept = false; if (energyDelta > 0) { if (i == 0 && j == 0) { deltaEAvg = deltaAbs * 15; } var p = Math.Pow(Math.E, -deltaAbs / (deltaEAvg * t)); if (Random.NextDouble() < p) { accept = true; } } else { accept = true; } if (accept) { acceptedSolutions++; currentLayout = perturbedLayout; deltaEAvg = (deltaEAvg * (acceptedSolutions - 1) + deltaAbs) / acceptedSolutions; #region Random restarts if (enableRandomRestarts && randomRestartsSuccessPlace == RestartSuccessPlace.OnAccepted) { wasAccepted = true; if (randomRestartsResetCounter) { numberOfFailures = 0; } } #endregion } } if (!wasAccepted) { numberOfFailures++; } t = t * ratio; } }
private void SetupGenerator() { var mapping = levelDescriptionMapped.GetMapping(); var chainsGeneric = configuration.Chains; // Create chain decomposition if (chainsGeneric == null) { var chainDecomposition = new Common.TwoStageChainDecomposition <TRoom>(levelDescription, new BreadthFirstChainDecomposition <TRoom>(configuration.ChainDecompositionConfiguration ?? new ChainDecompositionConfiguration())); chainsGeneric = chainDecomposition.GetChains(levelDescription.GetGraph()); } var chains = chainsGeneric .Select(x => new Chain <RoomNode <TRoom> >(x.Nodes.Select(y => mapping[y]).ToList(), x.Number) { IsFromFace = x.IsFromFace }) .ToList(); // Create generator planner var generatorPlanner = new GeneratorPlanner <Layout <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >, RoomNode <TRoom> >(configuration.SimulatedAnnealingMaxBranching); // Create configuration spaces var configurationSpacesGenerator = new ConfigurationSpacesGenerator( new PolygonOverlap(), DoorHandler.DefaultHandler, new OrthogonalLineIntersection(), new GridPolygonUtils()); // var configurationSpaces = configurationSpacesGenerator.GetConfigurationSpaces<ConfigurationNew2<CorridorsDataNew>>(mapDescription); var simpleConfigurationSpaces = new ConfigurationSpacesGrid2D <ConfigurationGrid2D <TRoom, EnergyData>, RoomNode <TRoom> >(levelDescriptionMapped); // Needlessly complex for backwards compatibility #region IntAliasMapping var roomDescriptions = levelDescriptionMapped.GetGraph().Vertices.ToDictionary(x => x, x => (RoomDescriptionGrid2D)levelDescriptionMapped.GetRoomDescription(x)); var roomTemplates = roomDescriptions.Values.SelectMany(x => x.RoomTemplates).Distinct().ToList(); var roomTemplateInstances = roomTemplates.ToDictionary(x => x, configurationSpacesGenerator.GetRoomTemplateInstances); var roomTemplateInstancesMapping = roomTemplateInstances.SelectMany(x => x.Value).CreateIntMapping(); var intAliasMapping = new TwoWayDictionary <RoomTemplateInstanceGrid2D, IntAlias <PolygonGrid2D> >(); foreach (var shape1 in roomTemplateInstancesMapping.Keys) { foreach (var shape2 in roomTemplateInstancesMapping.Keys) { if (!intAliasMapping.ContainsKey(shape1)) { var newAlias = new IntAlias <PolygonGrid2D>(intAliasMapping.Count, shape1.RoomShape); intAliasMapping.Add(shape1, newAlias); shape1.RoomShapeAlias = newAlias; } if (!intAliasMapping.ContainsKey(shape2)) { var newAlias = new IntAlias <PolygonGrid2D>(intAliasMapping.Count, shape2.RoomShape); intAliasMapping.Add(shape2, newAlias); shape2.RoomShapeAlias = newAlias; } } } // TODO: remove when possible foreach (var pair in intAliasMapping) { pair.Key.RoomShapeAlias = pair.Value; } var shapesForNodes = new Dictionary <RoomNode <TRoom>, List <WeightedShape> >(); foreach (var vertex in levelDescriptionMapped.GetGraph().Vertices) { shapesForNodes.Add(vertex, new List <WeightedShape>()); // var roomDescription = levelDescriptionMapped.GetRoomDescription(vertex); var roomDescription = roomDescriptions[vertex]; foreach (var roomTemplate in roomDescription.RoomTemplates) { var instances = roomTemplateInstances[roomTemplate]; foreach (var roomTemplateInstance in instances) { shapesForNodes[vertex].Add(new WeightedShape(intAliasMapping[roomTemplateInstance], 1d / instances.Count)); } } } var usedShapes = new HashSet <int>(); var allShapes = new List <IntAlias <PolygonGrid2D> >(); foreach (var vertex in levelDescriptionMapped.GetGraph().Vertices) { var shapes = shapesForNodes[vertex]; foreach (var shape in shapes) { if (!usedShapes.Contains(shape.Shape.Alias)) { allShapes.Add(shape.Shape); usedShapes.Add(shape.Shape.Alias); } } } var averageSize = (int)allShapes.Select(x => x.Value.BoundingRectangle).Average(x => (x.Width + x.Height) / 2); #endregion // var averageSize = configurationSpaces.GetAverageSize(); var energyUpdater = new BasicEnergyUpdater <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData> >(10 * averageSize); var roomShapeGeometry = new FastGridPolygonGeometry <ConfigurationGrid2D <TRoom, EnergyData>, RoomNode <TRoom> >(); // Create generator constraints var stageOneConstraints = new List <INodeConstraint <ILayout <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData> >, RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, EnergyData> > { new BasicConstraint <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, EnergyData>( roomShapeGeometry, simpleConfigurationSpaces, levelDescriptionMapped, configuration.OptimizeCorridorConstraints ), new CorridorConstraint <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, EnergyData>( levelDescriptionMapped, simpleConfigurationSpaces, roomShapeGeometry ), }; if (levelDescription.MinimumRoomDistance > 0) { stageOneConstraints.Add(new MinimumDistanceConstraint <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, EnergyData>( levelDescriptionMapped, roomShapeGeometry, levelDescription.MinimumRoomDistance )); } var constraintsEvaluator = new ConstraintsEvaluator <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, EnergyData>(stageOneConstraints, energyUpdater); var roomShapesHandler = new RoomShapesHandlerGrid2D <RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData> >( intAliasMapping, levelDescriptionMapped, shapesForNodes, levelDescription.RoomTemplateRepeatModeOverride, levelDescription.RoomTemplateRepeatModeDefault ); // Create layout operations var layoutOperations = new LayoutController <Layout <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >, RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData>, RoomTemplateInstanceGrid2D, EnergyData>(averageSize, levelDescriptionMapped, constraintsEvaluator, roomShapesHandler, configuration.ThrowIfRepeatModeNotSatisfied, simpleConfigurationSpaces, roomShapeGeometry); var initialLayout = new Layout <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >(levelDescriptionMapped.GetGraph()); var layoutConverter = new BasicLayoutConverterGrid2D <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >(levelDescription, simpleConfigurationSpaces, intAliasMapping); // Create simulated annealing evolver var layoutEvolver = new Common.SimulatedAnnealingEvolver <Layout <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >, RoomNode <TRoom>, ConfigurationGrid2D <TRoom, EnergyData> >(layoutOperations, configuration.SimulatedAnnealingConfiguration, true); // Create the generator itself generator = new ChainBasedGenerator <Layout <TRoom, ConfigurationGrid2D <TRoom, EnergyData> >, LayoutGrid2D <TRoom>, RoomNode <TRoom> >(initialLayout, generatorPlanner, chains, layoutEvolver, layoutConverter); // Register event handlers generator.OnRandomInjected += (random) => { // ((IRandomInjectable)configurationSpaces).InjectRandomGenerator(random); ((IRandomInjectable)layoutOperations).InjectRandomGenerator(random); ((IRandomInjectable)layoutEvolver).InjectRandomGenerator(random); ((IRandomInjectable)layoutConverter).InjectRandomGenerator(random); ((IRandomInjectable)simpleConfigurationSpaces).InjectRandomGenerator(random); ((IRandomInjectable)roomShapesHandler).InjectRandomGenerator(random); }; generator.OnCancellationTokenInjected += (token) => { ((ICancellable)generatorPlanner).SetCancellationToken(token); ((ICancellable)layoutEvolver).SetCancellationToken(token); }; layoutEvolver.OnEvent += (sender, args) => OnSimulatedAnnealingEvent?.Invoke(sender, args); layoutEvolver.OnPerturbed += (sender, layout) => OnPerturbed?.Invoke(layoutConverter.Convert(layout, false)); layoutEvolver.OnPerturbed += (sender, layout) => OnPerturbedInternal?.Invoke(layout); layoutEvolver.OnValid += (sender, layout) => OnPartialValid?.Invoke(layoutConverter.Convert(layout, true)); generatorPlanner.OnLayoutGenerated += layout => OnValid?.Invoke(layoutConverter.Convert(layout, true)); }
private void PerturbedLayoutsHandler(TLayout layout) { OnPerturbed?.Invoke(layoutConverter.Convert(layout, false)); }