/// <summary> /// Generate the dungeon graph and layout /// </summary> /// <param name="totalTrials">number of trials used if any of the graph or map generation fails</param> /// <param name="graphTrials">number of trials to generate graph before consider it a fail</param> /// <param name="mapTrials">number of trials to generate the layout before consider it a fail</param> /// <returns>the generated graph and layout</returns> static DungeonResult generateDungeon(int totalTrials = 100, int graphTrials = 100, int mapTrials = 100) { MissionGraph.Graph resultGraph = null; LayoutGrammar.Map resultMap = null; for (int i = 0; i < totalTrials; i++) { MissionGraph.Generator mg = new MissionGraph.Generator(new Random()); mg.loadPatterns("grammar/"); for (int j = 0; j < graphTrials; j++) { resultGraph = mg.GenerateDungeon("graphStart.txt", "graphRecipe.txt"); if (resultGraph != null && Helper.checkIsSolvable(resultGraph, resultGraph.nodes[0])) { break; } else { resultGraph = null; } } if (resultGraph == null) { continue; } LayoutGrammar.Generator lg = new LayoutGrammar.Generator(new Random()); for (int j = 0; j < mapTrials; j++) { resultMap = lg.generateDungeon(resultGraph); if (resultMap != null && Helper.checkIsSolvable(resultMap.get2DMap(), resultMap.getCell(0))) { break; } else { resultMap = null; } } if (resultMap == null) { continue; } break; } return(new DungeonResult(resultGraph, resultMap)); }
/// <summary> /// apply that current pattern to a random subgraph in the mission graph (inplace change) /// </summary> /// <param name="graph">the current mission graph</param> /// <param name="maxConnection">maximum number of connection from any specific node (to help the layout generator)</param> public void ApplyPattern(Graph graph, int maxConnection = 4) { List <Graph> permutations = graph.GetPermutations(patternMatch.nodes.Count); Helper.ShuffleList(random, permutations); int maxAccessLevel = graph.GetHighestAccessLevel(); List <int> levels = new List <int>(); for (int i = 0; i <= maxAccessLevel; i++) { levels.Add(i); } Helper.ShuffleList(random, levels); Graph selectedSubgraph = new Graph(); foreach (Graph subgraph in permutations) { foreach (int level in levels) { patternMatch.relativeAccess = level; if (patternMatch.CheckSimilarity(subgraph) && CheckPatternApplicable(graph, maxConnection)) { selectedSubgraph = subgraph; break; } } if (selectedSubgraph.nodes.Count > 0) { break; } } if (selectedSubgraph.nodes.Count == 0) { return; } foreach (Node n in selectedSubgraph.nodes) { List <Node> children = n.GetFilteredChildren(selectedSubgraph); foreach (Node c in children) { n.RemoveLinks(c); } } Graph selectedPattern = patternApply[random.Next(patternApply.Count)]; for (int i = selectedSubgraph.nodes.Count; i < selectedPattern.nodes.Count; i++) { Node newNode = new Node(graph.nodes.Count, -1, selectedPattern.nodes[i].type); graph.nodes.Add(newNode); selectedSubgraph.nodes.Add(newNode); } for (int i = 0; i < selectedPattern.nodes.Count; i++) { selectedSubgraph.nodes[i] .AdjustAccessLevel(patternMatch.relativeAccess + selectedPattern.nodes[i].accessLevel); List <Node> children = selectedPattern.nodes[i].GetChildren(); foreach (Node c in children) { int index = selectedPattern.GetNodeIndex(c); selectedSubgraph.nodes[i].ConnectTo(selectedSubgraph.nodes[index]); } } }
/// <summary> /// A structure to hold both the mission graph and layout /// </summary> /// <param name="missionGraph">the generated mission graph</param> /// <param name="layoutMap">the level layout</param> public DungeonResult(MissionGraph.Graph missionGraph, LayoutGrammar.Map layoutMap) { this.missionGraph = missionGraph; this.layoutMap = layoutMap; }
/// <summary> /// Constructor for the pattern class /// </summary> /// <param name="random">the same random object used by all the patterns to be able to replicate results</param> public Pattern(Random random) { this.random = random; patternMatch = new Graph(); patternApply = new List <Graph>(); }