The mission graph class
        /// <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>();
 }