/// <summary>
        /// Adds corridor node greedily.
        /// </summary>
        /// <param name="layout"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        public bool AddCorridorGreedily(TLayout layout, TNode node)
        {
            var configurations = new List <TConfiguration>();
            var neighbors      = layout.Graph.GetNeighbours(node);

            foreach (var neighbor in neighbors)
            {
                if (layout.GetConfiguration(neighbor, out var configuration))
                {
                    configurations.Add(configuration);
                }
            }

            if (configurations.Count == 0)
            {
                throw new InvalidOperationException();
            }

            var foundValid   = false;
            var bestShape    = default(TShapeContainer);
            var bestPosition = new Vector2Int();

            var shapes = ConfigurationSpaces.GetShapesForNode(node).ToList();

            shapes.Shuffle(Random);

            foreach (var shape in shapes)
            {
                var intersection = ConfigurationSpaces.GetMaximumIntersection(CreateConfiguration(shape, new Vector2Int(), node), configurations, out var configurationsSatisfied);

                if (configurationsSatisfied != 2)
                {
                    continue;
                }

                intersection.Shuffle(Random);

                foreach (var intersectionLine in intersection)
                {
                    const int maxPoints = 20;

                    if (intersectionLine.Length > maxPoints)
                    {
                        var mod = intersectionLine.Length / maxPoints - 1;

                        for (var i = 0; i < maxPoints; i++)
                        {
                            var position = intersectionLine.GetNthPoint(i != maxPoints - 1 ? i * mod : intersectionLine.Length + 1);

                            var energyData = stageTwoConstraintsEvaluator.ComputeNodeEnergy(layout, CreateConfiguration(shape, position, node));

                            if (energyData.IsValid)
                            {
                                bestShape    = shape;
                                bestPosition = position;
                                foundValid   = true;
                                break;
                            }

                            if (foundValid)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        var points = intersectionLine.GetPoints();
                        points.Shuffle(Random);

                        foreach (var position in points)
                        {
                            var energyData = stageTwoConstraintsEvaluator.ComputeNodeEnergy(layout, CreateConfiguration(shape, position, node));

                            if (energyData.IsValid)
                            {
                                bestShape    = shape;
                                bestPosition = position;
                                foundValid   = true;
                                break;
                            }

                            if (foundValid)
                            {
                                break;
                            }
                        }
                    }

                    if (foundValid)
                    {
                        break;
                    }
                }
            }

            var newConfiguration = CreateConfiguration(bestShape, bestPosition, node);

            layout.SetConfiguration(node, newConfiguration);

            return(foundValid);
        }
        /// <summary>
        /// Tries all shapes and positions from the maximum intersection to find a configuration
        /// with the lowest energy.
        /// </summary>
        /// <param name="layout"></param>
        /// <param name="node"></param>
        public override void AddNodeGreedily(TLayout layout, TNode node, out int iterationsCount)
        {
            iterationsCount = 0;
            var neighborsConfigurations = new List <TConfiguration>();
            var neighbors = MapDescription.GetStageOneGraph().GetNeighbours(node);

            foreach (var neighbor in neighbors)
            {
                if (layout.GetConfiguration(neighbor, out var configuration))
                {
                    neighborsConfigurations.Add(configuration);
                }
            }

            // The first node is set to have a random shape and [0,0] position
            if (neighborsConfigurations.Count == 0)
            {
                layout.SetConfiguration(node, CreateConfiguration(ConfigurationSpaces.GetRandomShape(node), new Vector2Int(), node));
                iterationsCount++;
                return;
            }

            var bestEnergy   = float.MaxValue;
            var bestShape    = default(TShapeContainer);
            var bestPosition = new Vector2Int();

            var shapes = RoomShapesHandler.GetPossibleShapesForNode(layout, node, !throwIfRepeatModeNotSatisfied);

            if (shapes.Count == 0)
            {
                if (throwIfRepeatModeNotSatisfied)
                {
                    throw new InvalidOperationException($"It was not possible to assign room shapes in a way that satisfies all the RepeatMode requirements. Moreover, the {nameof(throwIfRepeatModeNotSatisfied)} option is set to true which means that the algorithm did not attempt to find at least some room templates even though not all conditions were satisfied. Please make sure that there are enough room templates to choose from. Problematic room: {node}.");
                }
                else
                {
                    throw new InvalidOperationException($"It was not possible to assign room shapes in a way that satisfies all the RepeatMode requirements.  Please make sure that there are enough room templates to choose from. Problematic room: {node}.");
                }
            }

            shapes.Shuffle(Random);

            // Try all shapes
            foreach (var shape in shapes)
            {
                var intersection = ConfigurationSpaces.GetMaximumIntersection(CreateConfiguration(shape, new Vector2Int(), node), neighborsConfigurations);

                if (intersection == null)
                {
                    continue;
                }

                intersection.Shuffle(Random);

                // Try all lines from the maximum intersection
                foreach (var intersectionLine in intersection)
                {
                    // Limit the number of points to 20.
                    // It is very slow to try all the positions if rooms are big.
                    const int maxPoints = 20;

                    if (intersectionLine.Length > maxPoints)
                    {
                        var mod = intersectionLine.Length / maxPoints - 1;

                        for (var i = 0; i < maxPoints; i++)
                        {
                            iterationsCount++;

                            var position = intersectionLine.GetNthPoint(i != maxPoints - 1 ? i * mod : intersectionLine.Length);

                            var energy = stageOneConstraintsEvaluator.ComputeNodeEnergy(layout, CreateConfiguration(shape, position, node)).Energy;

                            if (energy < bestEnergy)
                            {
                                bestEnergy   = energy;
                                bestShape    = shape;
                                bestPosition = position;
                            }

                            if (bestEnergy <= 0)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        iterationsCount++;

                        var points = intersectionLine.GetPoints();
                        points.Shuffle(Random);

                        foreach (var position in points)
                        {
                            var energy = stageOneConstraintsEvaluator.ComputeNodeEnergy(layout, CreateConfiguration(shape, position, node)).Energy;

                            if (energy < bestEnergy)
                            {
                                bestEnergy   = energy;
                                bestShape    = shape;
                                bestPosition = position;
                            }

                            if (bestEnergy <= 0)
                            {
                                break;
                            }
                        }
                    }

                    // There is no point of looking for more solutions when you already reached a valid state
                    // and so no position would be accepted anyway
                    if (bestEnergy <= 0)
                    {
                        break;
                    }
                }
            }

            if (bestEnergy == float.MaxValue)
            {
                throw new ArgumentException($"No shape of the room {node} could be connected to its neighbors. This usually happens if there are pairs of shapes that cannot be connected together in any way (either directly or via corridors). (The mentioned room may not correspond to the actual room as custom types are often mapped to integers to make the computation faster.)");
            }

            var newConfiguration = CreateConfiguration(bestShape, bestPosition, node);

            layout.SetConfiguration(node, newConfiguration);
        }
Example #3
0
 public IList <TShapeContainer> GetShapesForNode(TNode node)
 {
     return(ConfigurationSpaces.GetShapesForNode(node).ToList());
 }
Example #4
0
 public IntVector2 GetRandomPosition(TShapeContainer shape, IList <TConfiguration> configurations)
 {
     return(ConfigurationSpaces.GetRandomIntersectionPoint(CreateConfiguration(shape, new IntVector2()), configurations));
 }
Example #5
0
        /// <summary>
        /// Greedily adds non corridor node to the layout.
        /// </summary>
        /// <remarks>
        /// Uses special configuration spaces where shapes are not directly connected
        /// but are rather at a specified distance from each other.
        /// </remarks>
        /// <param name="layout"></param>
        /// <param name="node"></param>
        private void AddNonCorridorGreedily(TLayout layout, TNode node)
        {
            var configurations = GetNeighboursOverCorridors(layout, node);

            if (configurations.Count == 0)
            {
                layout.SetConfiguration(node, CreateConfiguration(ConfigurationSpaces.GetRandomShape(node), new IntVector2()));
                return;
            }

            var bestEnergy   = float.MaxValue;
            var bestShape    = default(TShapeContainer);
            var bestPosition = new IntVector2();

            var shapes = ConfigurationSpaces.GetShapesForNode(node).ToList();

            shapes.Shuffle(Random);

            foreach (var shape in shapes)
            {
                var intersection = CorridorConfigurationSpaces.GetMaximumIntersection(CreateConfiguration(shape, new IntVector2()), configurations);

                if (intersection == null)
                {
                    continue;
                }

                intersection.Shuffle(Random);

                foreach (var intersectionLine in intersection)
                {
                    var       tryAll    = true;
                    var       mod       = 1;
                    const int maxPoints = 20;

                    if (intersectionLine.Length > maxPoints)
                    {
                        tryAll = false;
                        mod    = intersectionLine.Length / maxPoints;
                    }

                    var i = 0;

                    foreach (var position in intersectionLine.GetPoints())
                    {
                        if (!tryAll && i % mod != 0 && i != intersectionLine.Length)
                        {
                            continue;
                        }

                        var energy = NodeComputeEnergyData(layout, node, CreateConfiguration(shape, position)).Energy;

                        if (energy < bestEnergy)
                        {
                            bestEnergy   = energy;
                            bestShape    = shape;
                            bestPosition = position;
                        }

                        if (bestEnergy <= 0)
                        {
                            break;
                        }

                        i++;
                    }

                    // There is no point of looking for more solutions when you already reached a valid state
                    // and so no position would be accepted anyway
                    // TODO: What about making it somehow random? If there are more valid positions, choose one at random.
                    if (bestEnergy <= 0)
                    {
                        break;
                    }
                }
            }

            var newConfiguration = CreateConfiguration(bestShape, bestPosition);

            layout.SetConfiguration(node, newConfiguration);
        }
        /// <summary>
        /// Tries all shapes and positions from the maximum intersection to find a configuration
        /// with the lowest energy.
        /// </summary>
        /// <param name="layout"></param>
        /// <param name="node"></param>
        public override void AddNodeGreedily(TLayout layout, TNode node)
        {
            var configurations = new List <TConfiguration>();
            var neighbours     = layout.Graph.GetNeighbours(node);

            foreach (var neighbour in neighbours)
            {
                if (layout.GetConfiguration(neighbour, out var configuration))
                {
                    configurations.Add(configuration);
                }
            }

            // The first node is set to have a random shape and [0,0] position
            if (configurations.Count == 0)
            {
                layout.SetConfiguration(node, CreateConfiguration(ConfigurationSpaces.GetRandomShape(node), new IntVector2()));
                return;
            }

            var bestEnergy   = float.MaxValue;
            var bestShape    = default(TShapeContainer);
            var bestPosition = new IntVector2();

            var shapes = ConfigurationSpaces.GetShapesForNode(node).ToList();

            // shapes.Shuffle(Random);

            // Try all shapes
            foreach (var shape in shapes)
            {
                var intersection = ConfigurationSpaces.GetMaximumIntersection(CreateConfiguration(shape, new IntVector2()), configurations);

                // Try all lines from the maximum intersection
                foreach (var intersectionLine in intersection)
                {
                    // Limit the number of points to 20.
                    // It is very slow to try all the positions if rooms are big.
                    const int maxPoints = 20;

                    if (intersectionLine.Length > maxPoints)
                    {
                        var mod = intersectionLine.Length / maxPoints - 1;

                        for (var i = 0; i < maxPoints; i++)
                        {
                            var position = intersectionLine.GetNthPoint(i != maxPoints - 1 ? i * mod : intersectionLine.Length);

                            var energy = NodeComputeEnergyData(layout, node, CreateConfiguration(shape, position)).Energy;

                            if (energy < bestEnergy)
                            {
                                bestEnergy   = energy;
                                bestShape    = shape;
                                bestPosition = position;
                            }

                            if (bestEnergy <= 0)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        var points = intersectionLine.GetPoints();
                        points.Shuffle(Random);

                        foreach (var position in points)
                        {
                            var energy = NodeComputeEnergyData(layout, node, CreateConfiguration(shape, position)).Energy;

                            if (energy < bestEnergy)
                            {
                                bestEnergy   = energy;
                                bestShape    = shape;
                                bestPosition = position;
                            }

                            if (bestEnergy <= 0)
                            {
                                break;
                            }
                        }
                    }

                    // There is no point of looking for more solutions when you already reached a valid state
                    // and so no position would be accepted anyway
                    if (bestEnergy <= 0)
                    {
                        break;
                    }
                }
            }

            var newConfiguration = CreateConfiguration(bestShape, bestPosition);

            layout.SetConfiguration(node, newConfiguration);
        }