/// <inheritdoc /> public bool ComputeEnergyData(TLayout layout, TNode node, TConfiguration configuration, ref TEnergyData energyData) { if (mapDescription.IsCorridorRoom(node)) { return(true); } var distance = 0; var neighbours = graphWithoutCorridors.GetNeighbours(node).ToList(); foreach (var vertex in neighbours) { if (vertex.Equals(node)) { continue; } if (!layout.GetConfiguration(vertex, out var c)) { continue; } if (!configurationSpaces.HaveValidPosition(configuration, c)) { distance += ComputeDistance(configuration, c); } } var energy = ComputeEnergy(0, distance); energyData.CorridorDistance = distance; energyData.Energy += energy; return(distance == 0); }
/// <summary> /// Perturbs non corridor rooms until a valid layout is found. /// Then tries to use a greedy algorithm to lay out corridor rooms. /// </summary> /// <param name="layout"></param> /// <param name="chain"></param> /// <param name="updateLayout"></param> public override void PerturbLayout(TLayout layout, IList <TNode> chain, bool updateLayout) { if (!MapDescription.IsWithCorridors) { base.PerturbLayout(layout, chain, updateLayout); return; } var nonCorridors = chain.Where(x => !MapDescription.IsCorridorRoom(x)).ToList(); var firstCorridor = chain.First(x => MapDescription.IsCorridorRoom(x)); if (layout.GetConfiguration(firstCorridor, out var _)) { foreach (var corridor in chain.Where(x => MapDescription.IsCorridorRoom(x))) { layout.RemoveConfiguration(corridor); } } if (Random.NextDouble() < 0.4f) { PerturbShape(layout, nonCorridors, updateLayout); } else { var random = nonCorridors.GetRandom(Random); PerturbNonCorridorPosition(layout, random, updateLayout); } }
/// <inheritdoc /> public bool ComputeEnergyData(TLayout layout, TNode node, TConfiguration configuration, ref TEnergyData energyData) { if (mapDescription.IsCorridorRoom(node)) { return(true); } var numberOfTouching = 0; foreach (var vertex in layout.Graph.Vertices) { if (vertex.Equals(node)) { continue; } if (!layout.GetConfiguration(vertex, out var c)) { continue; } if (mapDescription.IsCorridorRoom(vertex)) { continue; } if (DoTouch(configuration, c)) { numberOfTouching++; } } energyData.NumberOfTouching = numberOfTouching; energyData.Energy += numberOfTouching; return(numberOfTouching == 0); }
/// <inheritdoc /> /// <summary> /// Finds the smallest feasible multiple of a specified number and then make from it a sequence of corridors. /// </summary> public void AddCorridorsToMapping(ICorridorMapDescription <int> mapDescription, TwoWayDictionary <int, int> mapping) { var graph = mapDescription.GetGraph(); var corridors = graph.Vertices.Where(mapDescription.IsCorridorRoom).ToList(); var maxNonCorridorNumber = graph.Vertices.Where(x => !mapDescription.IsCorridorRoom(x)).Max(); var parts = maxNonCorridorNumber / roundTo; var nextNumber = roundTo * (parts + 1); var counter = nextNumber; foreach (var corridor in corridors) { mapping.Add(counter++, corridor); } }
/// <inheritdoc /> public List <List <TNode> > GetChains(IGraph <TNode> graph) { if (!mapDescription.IsWithCorridors) { throw new InvalidOperationException("Map description must be with corridors to use this decomposition."); } var graphWithoutCorridors = mapDescription.GetGraphWithoutCorrridors(); var faces = decomposition.GetChains(graphWithoutCorridors); var usedVertices = new HashSet <TNode>(); var corridors = graph.Vertices.Where(x => mapDescription.IsCorridorRoom(x)).ToList(); foreach (var face in faces) { face.ForEach(x => usedVertices.Add(x)); var corridorsToRemove = new List <TNode>(); foreach (var corridor in corridors) { var neighbours = graph.GetNeighbours(corridor).ToList(); if (neighbours.Count != 2) { throw new ArgumentException("Every corridor must have exactly two neighbours"); } if (usedVertices.Contains(neighbours[0]) && usedVertices.Contains(neighbours[1])) { corridorsToRemove.Add(corridor); face.Add(corridor); } } corridorsToRemove.ForEach(x => corridors.Remove(x)); } if (corridors.Count != 0) { throw new ArgumentException(); } return(faces); }