コード例 #1
0
        private IDictionary <string, GameObject[]> BreadthFirstSpaceGeneration(GraphType graph, NodeType startNode)
        {
            IDictionary <string, GameObject[]> generatedSpace = new Dictionary <string, GameObject[]>(graph.Nodes.Node.Length);
            Queue <string> nodeIdQueue = new Queue <string>();

            GameObject[] startNodeSpaceObjects = BuildSpaceForMissionSymbol(startNode.symbol);
            generatedSpace[startNode.id] = startNodeSpaceObjects;
            nodeIdQueue.Enqueue(startNode.id);

            while (nodeIdQueue.Count != 0)
            {
                string           currentNodeId = nodeIdQueue.Dequeue();
                IList <NodeType> adjacentNodes = graph.AdjacencyList[currentNodeId];
                foreach (NodeType adjacentNode in adjacentNodes)
                {
                    if (generatedSpace.ContainsKey(adjacentNode.id))
                    {
                        continue;
                    }
                    GameObject[] currentNodeSpaceObjects  = generatedSpace[currentNodeId];
                    GameObject[] adjacentNodeSpaceObjects = BuildSpaceForMissionSymbol(
                        adjacentNode.symbol, currentNodeSpaceObjects);
                    generatedSpace[adjacentNode.id] = adjacentNodeSpaceObjects;
                    nodeIdQueue.Enqueue(adjacentNode.id);
                }
            }

            return(generatedSpace);
        }
コード例 #2
0
        private void ConnectFinalKeyToFinalLock(GraphType missionGraph,
                                                IDictionary <string, GameObject[]> generatedSpace)
        {
            IList <NodeType> lockFinalNodes = missionGraph.NodeSymbolMap[lockFinalSymbol];

            if (lockFinalNodes.Count != 1)
            {
                throw new InvalidOperationException("Cannot connect final lock to final key due to the wrong " +
                                                    "number of lock nodes in mission graph corresponding to the lock " +
                                                    $"final symbol '{lockFinalSymbol}'. Expected 1 but found " +
                                                    $"{lockFinalNodes.Count}.");
            }

            IList <NodeType> keyFinalNodes = missionGraph.NodeSymbolMap[keyFinalSymbol];

            if (keyFinalNodes.Count != 1)
            {
                throw new InvalidOperationException("Cannot connect final lock to final key due to the wrong " +
                                                    "number of key nodes in mission graph corresponding to the key " +
                                                    $"final symbol '{keyFinalSymbol}'. Expected 1 but found " +
                                                    $"{keyFinalNodes.Count}.");
            }

            ConnectLockAndKey(generatedSpace, lockFinalNodes[0].id, keyFinalNodes[0].id);
        }
コード例 #3
0
        public GraphType GenerateGraph()
        {
            IDictionary <string, GraphType> graphs = new Dictionary <string, GraphType>(Graphs.Graph.Length);

            foreach (GraphType graph in Graphs.Graph)
            {
                graphs[graph.id] = graph;
            }

            string    startGraphRef = Grammar.StartGraph.@ref;
            GraphType startGraph    = graphs[startGraphRef];

            int ruleNumber = 0;

            while (true)
            {
                RuleType[] applicableRules = GetApplicableRules(graphs, startGraph);
                if (applicableRules.Length == 0)
                {
                    return(startGraph);
                }

                RuleType ruleToApply = applicableRules[
                    applicableRules.Length == 1 ? 0 : Random.Range(0, applicableRules.Length)];

                Debug.Log($"[Applying Rule {++ruleNumber}] source: {ruleToApply.source} | target: {ruleToApply.target}");

                GraphType ruleSource = graphs[ruleToApply.source];
                GraphType ruleTarget = graphs[ruleToApply.target];
                startGraph.FindAndReplace(ruleSource, ruleTarget);
            }
        }
コード例 #4
0
 private void PostProcess(GraphType missionGraph, IDictionary <string, GameObject[]> generatedSpace)
 {
     foreach (PostProcessor postProcessor in GetComponents <PostProcessor>())
     {
         postProcessor.Process(missionGraph, generatedSpace);
     }
 }
コード例 #5
0
        /**
         * Copy the edges from targetGraph into this graph, determining the source and target nodes from markedNodes
         */
        private void InsertEdgesBetweenMarkedNodes(GraphType otherGraph, IDictionary <string, NodeType> markedNodes)
        {
            if (otherGraph.Edges?.Edge == null || otherGraph.Edges?.Edge?.Length == 0)
            {
                return;
            }

            IList <EdgeType> edges = Edges?.Edge != null
                ? new List <EdgeType>(Edges.Edge)
                : new List <EdgeType>(otherGraph.Edges.Edge.Length);

            foreach (EdgeType targetGraphEdge in otherGraph.Edges.Edge)
            {
                string source = targetGraphEdge.source;
                string target = targetGraphEdge.target;

                edges.Add(new EdgeType
                {
                    source = markedNodes[source].id,
                    target = markedNodes[target].id
                });
            }

            if (Edges == null)
            {
                Edges = new EdgesType();
            }
            Edges.Edge = edges.ToArray();
        }
コード例 #6
0
        private void ConnectMultiKeysToMultiLock(GraphType missionGraph,
                                                 IDictionary <string, GameObject[]> generatedSpace)
        {
            IList <NodeType> lockMultiNodes = missionGraph.NodeSymbolMap[lockMultiSymbol];

            if (lockMultiNodes.Count != 1)
            {
                throw new InvalidOperationException("Cannot connect multi keys to multi lock due to the wrong " +
                                                    "number of lock nodes in mission graph corresponding to the lock " +
                                                    $"final symbol '{lockMultiSymbol}'. Expected 1 but found " +
                                                    $"{lockMultiNodes.Count}.");
            }

            string lockId = lockMultiNodes[0].id;

            GameObject[] locks = GetLocks(generatedSpace, lockId);
            if (locks.Length != 1)
            {
                throw new InvalidOperationException($"Cannot connect multi keys to multi lock (ID: {lockId}) " +
                                                    "due to the wrong number of lock GameObjects corresponding to " +
                                                    $"the lock's ID. Expected 1 but found {locks.Length}.");
            }

            Item[] keys = missionGraph.NodeSymbolMap[keyMultiSymbol]
                          .SelectMany(node => generatedSpace[node.id])
                          .SelectMany(spaceObject => spaceObject.transform.Cast <Transform>())
                          .Where(child => child.CompareTag("Key"))
                          .Select(keyTransform => keyTransform.GetComponent <Item>())
                          .ToArray();

            locks[0].GetComponent <UnlockDoorAction>().AddRequiredKeys(keys);
        }
コード例 #7
0
        private bool SubgraphSearch(GraphType otherGraph, IDictionary <string, IList <NodeType> > markedNodes = null)
        {
            foreach (NodeType startNode in otherGraph.StartNodes)
            {
                IList <NodeType> sourceNodes = new List <NodeType> {
                    startNode
                };
                IList <NodeType> nodeCandidates = NodeSymbolMap[startNode.symbol];

                bool markNodesForAllNodeCandidates = markedNodes != null && nodeCandidates.Count > 1;
                IList <IDictionary <string, IList <NodeType> > > markedNodesList = markNodesForAllNodeCandidates
                    ? new List <IDictionary <string, IList <NodeType> > >()
                    : null;

                bool successfulCandidateFound = false;

                foreach (NodeType nodeCandidate in nodeCandidates)
                {
                    IList <NodeType> thisNodes = new List <NodeType> {
                        nodeCandidate
                    };

                    IDictionary <string, IList <NodeType> > candidateMarkedNodes = markNodesForAllNodeCandidates
                        ? new Dictionary <string, IList <NodeType> >()
                        : markedNodes;

                    bool isSuccessfulCandidate = SubgraphSearch(otherGraph, thisNodes, sourceNodes, candidateMarkedNodes);
                    if (isSuccessfulCandidate)
                    {
                        successfulCandidateFound = true;
                        if (!markNodesForAllNodeCandidates)
                        {
                            break;                                 // not marking nodes for all candidates means we don't need to search every node, so break
                        }
                        markedNodesList.Add(candidateMarkedNodes);
                    }
                }

                if (!successfulCandidateFound)
                {
                    return(false);
                }

                if (markNodesForAllNodeCandidates)
                {
                    // pick a random collection of marked nodes to use and add contents to original markedNodes Dictionary
                    IDictionary <string, IList <NodeType> > markedNodesToUse =
                        markedNodesList[Random.Range(0, markedNodesList.Count)];

                    foreach (KeyValuePair <string, IList <NodeType> > keyValuePair in markedNodesToUse)
                    {
                        markedNodes[keyValuePair.Key] = keyValuePair.Value;
                    }
                }
            }

            return(true);
        }
コード例 #8
0
        public void FindAndReplace(GraphType sourceGraph, GraphType targetGraph)
        {
            IDictionary <string, NodeType> markedNodes = FindSubgraphAndMarkNodes(sourceGraph);

            RemoveEdgesBetweenMarkedNodes(sourceGraph, markedNodes);
            FindAndReplaceNodes(sourceGraph, targetGraph, markedNodes);
            InsertEdgesBetweenMarkedNodes(targetGraph, markedNodes);
            RecalculateFields();
        }
コード例 #9
0
 private RuleType[] GetApplicableRules(IDictionary <string, GraphType> graphs, GraphType startGraph)
 {
     return(Grammar.Rules.Rule
            .Where(rule =>
     {
         GraphType ruleSourceGraph = graphs[rule.source];
         return startGraph.IsSupergraphOf(ruleSourceGraph);
     })
            .ToArray());
 }
コード例 #10
0
 private bool HasAllSymbolsIn(GraphType otherGraph)
 {
     return(otherGraph.NodeSymbolMap.All(pair =>
     {
         string symbol = pair.Key;
         IList <NodeType> otherGraphNodes = pair.Value;
         return NodeSymbolMap.ContainsKey(symbol) &&
         NodeSymbolMap[symbol].Count >= otherGraphNodes.Count;
     }));
 }
コード例 #11
0
        /**
         * Carry out a BFS through missionGraph. For each node, retrieve the correct SpaceObjectByMissionSymbol based
         * on the node's symbol and place the SpaceObject on the plane of the scene, connecting it to an existing
         * SpaceObject where possible (e.g. not the first SpaceObject placed, and only connected where specified by the
         * SpaceObject - such as a doorway).
         */
        private IDictionary <string, GameObject[]> GenerateSpace(GraphType missionGraph)
        {
            int numStartNodes = missionGraph.StartNodes.Length;

            if (numStartNodes > 1)
            {
                throw new InvalidOperationException("Mission graph cannot have more than 1 start node. " +
                                                    $"It currently has {numStartNodes}.");
            }
            return(BreadthFirstSpaceGeneration(missionGraph, missionGraph.StartNodes[0]));
        }
コード例 #12
0
        public override void Process(GraphType missionGraph, IDictionary <string, GameObject[]> generatedSpace)
        {
            playerController = GameObject.FindWithTag("Player").GetComponent <PlayerController>();

            if (missionGraph.NodeSymbolMap.ContainsKey(questItemSymbol))
            {
                CreateQuestsForQuestItems(missionGraph, generatedSpace);
            }

            if (missionGraph.NodeSymbolMap.ContainsKey(levelBossSymbol))
            {
                CreateQuestsForLevelBoss(missionGraph, generatedSpace);
            }
        }
コード例 #13
0
        /**
         * Transform this graph by transforming marked nodes into their corresponding nodes
         * in targetGraph, adding a node for each node in targetGraph that has no match in
         * this graph, and removing any nodes that have no corresponding node in targetGraph.
         */
        private void FindAndReplaceNodes(GraphType sourceGraph, GraphType targetGraph,
                                         IDictionary <string, NodeType> markedNodes)
        {
            List <NodeType> thisGraphNodes = new List <NodeType>(Nodes.Node);

            foreach (NodeType targetGraphNode in targetGraph.Nodes.Node)
            {
                string nodeId    = targetGraphNode.id;
                string newSymbol = targetGraphNode.symbol;
                if (markedNodes.ContainsKey(nodeId))
                {
                    markedNodes[nodeId].symbol = newSymbol;
                }
                else
                {
                    List <int> numericIds = new List <int>(thisGraphNodes.Count);
                    foreach (NodeType node in thisGraphNodes)
                    {
                        if (int.TryParse(node.id, out int idAsInt))
                        {
                            numericIds.Add(idAsInt);
                        }
                    }

                    int newNodeId = 0;
                    if (numericIds.Count > 0)
                    {
                        numericIds.Sort();
                        newNodeId = numericIds.Last() + 1;
                    }

                    NodeType newNode = new NodeType
                    {
                        id     = newNodeId.ToString(),
                        symbol = newSymbol
                    };

                    thisGraphNodes.Add(newNode);
                    markedNodes[nodeId] = newNode;
                }
            }

            IEnumerable <string> nodesToRemove = sourceGraph.Nodes.Node
                                                 .Where(sourceNode => targetGraph.Nodes.Node.All(targetNode => targetNode.id != sourceNode.id))
                                                 .Select(sourceNode => markedNodes[sourceNode.id].id);

            thisGraphNodes.RemoveAll(node => nodesToRemove.Contains(node.id));

            Nodes.Node = thisGraphNodes.ToArray();
        }
コード例 #14
0
        private bool SubgraphSearch(GraphType otherGraph, IList <NodeType> thisNodes, IList <NodeType> otherNodes,
                                    IDictionary <string, IList <NodeType> > markedNodes = null, IList <string> visitedOtherNodes = null)
        {
            visitedOtherNodes = visitedOtherNodes ?? new List <string>(otherGraph.Nodes.Node.Length);

            foreach (NodeType otherNode in otherNodes)
            {
                if (visitedOtherNodes.Contains(otherNode.id))
                {
                    continue;
                }
                visitedOtherNodes.Add(otherNode.id);
                IList <string> visitedOtherNodesThusFar = new List <string>(visitedOtherNodes);

                bool matchingNodeFound = false;
                foreach (NodeType thisNode in thisNodes)
                {
                    if (thisNode.symbol != otherNode.symbol)
                    {
                        continue;
                    }

                    IList <NodeType> thisAdjacentNodes  = AdjacencyList[thisNode.id];
                    IList <NodeType> otherAdjacentNodes = otherGraph.AdjacencyList[otherNode.id];
                    matchingNodeFound = SubgraphSearch(otherGraph, thisAdjacentNodes,
                                                       otherAdjacentNodes, markedNodes, visitedOtherNodes);

                    if (!matchingNodeFound)
                    {
                        visitedOtherNodes = new List <string>(visitedOtherNodesThusFar);
                    }
                    else if (markedNodes != null)
                    {
                        if (!markedNodes.ContainsKey(otherNode.id))
                        {
                            markedNodes[otherNode.id] = new List <NodeType>();
                        }
                        markedNodes[otherNode.id].Add(thisNode);
                    }
                }

                if (!matchingNodeFound)
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #15
0
        private void RemoveEdgesBetweenMarkedNodes(GraphType otherGraph, IDictionary <string, NodeType> markedNodes)
        {
            if (Edges?.Edge == null || otherGraph.Edges?.Edge == null)
            {
                return;
            }
            List <EdgeType> edges = new List <EdgeType>(Edges.Edge);

            foreach (EdgeType sourceGraphEdge in otherGraph.Edges.Edge)
            {
                string sourceNodeId = markedNodes[sourceGraphEdge.source].id;
                string targetNodeId = markedNodes[sourceGraphEdge.target].id;
                edges.RemoveAll(edge => edge.source == sourceNodeId && edge.target == targetNodeId);
            }

            Edges.Edge = edges.ToArray();
        }
コード例 #16
0
        public override void Process(GraphType missionGraph, IDictionary <string, GameObject[]> generatedSpace)
        {
            if (missionGraph.HasNodesForSymbols(lockSymbol, keySymbol))
            {
                ConnectKeysToLocks(missionGraph, generatedSpace);
            }

            if (missionGraph.HasNodesForSymbols(lockMultiSymbol, keyMultiSymbol))
            {
                ConnectMultiKeysToMultiLock(missionGraph, generatedSpace);
            }

            if (missionGraph.HasNodesForSymbols(lockFinalSymbol, keyFinalSymbol))
            {
                ConnectFinalKeyToFinalLock(missionGraph, generatedSpace);
            }
        }
コード例 #17
0
        // TODO: remove this method when done prototyping
        private void DebugLogGraph(GraphType graph)
        {
            foreach (NodeType node in graph.Nodes.Node)
            {
                Debug.Log($"[Graph {graph.id} | Node: {node.id}] symbol: {node.symbol}");
            }

            if (graph.Edges?.Edge == null)
            {
                return;
            }
            for (int j = 0; j < graph.Edges.Edge.Length; j++)
            {
                EdgeType edge = graph.Edges.Edge[j];
                Debug.Log($"[Graph {graph.id} | Edge: {j + 1}] source: {edge.source} | target: {edge.target}");
            }
        }
コード例 #18
0
        private void Start()
        {
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start();

            long timeBeforeXmlDeserialization = stopwatch.ElapsedMilliseconds;

            GenGraType genGra = DeserializeGenGraXML();

            long timeAfterXmlDeserialization = stopwatch.ElapsedMilliseconds;
            long xmlDeserializationTime      = timeAfterXmlDeserialization - timeBeforeXmlDeserialization;

            Debug.Log($"XML deserialization completed in: {xmlDeserializationTime}ms");

            long timeBeforeGraphTransformation = stopwatch.ElapsedMilliseconds;

            GraphType missionGraph = genGra.GenerateGraph();

            long timeAfterGraphTransformation = stopwatch.ElapsedMilliseconds;
            long graphTransformationTime      = timeAfterGraphTransformation - timeBeforeGraphTransformation;

            DebugLogGraph(missionGraph);
            Debug.Log($"Mission graph generation completed in: {graphTransformationTime}ms");

            long timeBeforeSpaceGeneration = stopwatch.ElapsedMilliseconds;

            IDictionary <string, GameObject[]> generatedSpace = GenerateSpace(missionGraph);

            long timeAfterSpaceGeneration = stopwatch.ElapsedMilliseconds;
            long spaceGenerationTime      = timeAfterSpaceGeneration - timeBeforeSpaceGeneration;

            Debug.Log($"Space generation completed in: {spaceGenerationTime}ms");

            long timeBeforePostProcessing = stopwatch.ElapsedMilliseconds;

            PostProcess(missionGraph, generatedSpace);

            long timeAfterPostProcessing = stopwatch.ElapsedMilliseconds;
            long postProcessingTime      = timeAfterPostProcessing - timeBeforePostProcessing;

            Debug.Log($"Post processing completed in: {postProcessingTime}ms");

            stopwatch.Stop();
            Debug.Log($"Total execution completed in: {stopwatch.ElapsedMilliseconds}ms");
        }
コード例 #19
0
        private void ConnectKeysToLocks(GraphType missionGraph, IDictionary <string, GameObject[]> generatedSpace)
        {
            IList <NodeType> usedLockNodes     = new List <NodeType>();
            IList <NodeType> suspendedKeyNodes = new List <NodeType>();

            IList <NodeType> keyNodes = missionGraph.NodeSymbolMap[keySymbol];

            foreach (NodeType keyNode in keyNodes)
            {
                bool             isLockNodeAdjacent = false;
                IList <NodeType> adjacentNodes      = missionGraph.AdjacencyList[keyNode.id];
                foreach (NodeType adjacentNode in adjacentNodes)
                {
                    if (adjacentNode.symbol == lockSymbol)
                    {
                        ConnectLockAndKey(generatedSpace, adjacentNode.id, keyNode.id);
                        usedLockNodes.Add(adjacentNode);
                        isLockNodeAdjacent = true;
                        break;
                    }
                }

                if (!isLockNodeAdjacent)
                {
                    suspendedKeyNodes.Add(keyNode);
                }
            }

            if (suspendedKeyNodes.Count == 0)
            {
                return;
            }

            List <NodeType> lockNodes = missionGraph.NodeSymbolMap[lockSymbol].ToList();

            lockNodes.RemoveAll(usedLockNodes.Contains);

            foreach (NodeType keyNode in suspendedKeyNodes)
            {
                NodeType randomLockNode = lockNodes[lockNodes.Count == 1 ? 0 : Random.Range(0, lockNodes.Count)];

                ConnectLockAndKey(generatedSpace, randomLockNode.id, keyNode.id);
                lockNodes.Remove(randomLockNode);
            }
        }
コード例 #20
0
 public override void Process(GraphType missionGraph, IDictionary <string, GameObject[]> generatedSpace)
 {
     foreach (GameObject[] spaceObjectList in generatedSpace.Values)
     {
         foreach (GameObject spaceObject in spaceObjectList)
         {
             foreach (Transform child in spaceObject.transform)
             {
                 if (child.CompareTag("Navigatable"))
                 {
                     NavMeshSurface navMeshSurface = child.GetComponent <NavMeshSurface>();
                     if (navMeshSurface != null)
                     {
                         navMeshSurface.BuildNavMesh();
                     }
                 }
             }
         }
     }
 }
コード例 #21
0
        private void CreateQuestsForQuestItems(GraphType missionGraph, IDictionary <string, GameObject[]> generatedSpace)
        {
            IList <NodeType> questItemNodes = missionGraph.NodeSymbolMap[questItemSymbol];

            foreach (NodeType questItemNode in questItemNodes)
            {
                GameObject[] spaceObjects = generatedSpace[questItemNode.id];
                foreach (GameObject spaceObject in spaceObjects)
                {
                    foreach (Transform child in spaceObject.transform)
                    {
                        if (child.CompareTag("Item"))
                        {
                            Item  item  = child.GetComponent <Item>();
                            Quest quest = new Quest($"Find {item.ItemName}");
                            item.Quest = quest;
                            playerController.AddQuest(quest);
                        }
                    }
                }
            }
        }
コード例 #22
0
        private void CreateQuestsForLevelBoss(GraphType missionGraph, IDictionary <string, GameObject[]> generatedSpace)
        {
            IList <NodeType> levelBossNodes = missionGraph.NodeSymbolMap[levelBossSymbol];

            foreach (NodeType levelBossNode in levelBossNodes)
            {
                GameObject[] spaceObjects = generatedSpace[levelBossNode.id];
                foreach (GameObject spaceObject in spaceObjects)
                {
                    foreach (Transform child in spaceObject.transform)
                    {
                        if (child.CompareTag("Enemy"))
                        {
                            Enemy enemy = child.GetComponent <Enemy>();
                            Quest quest = new Quest($"Defeat {enemy.EnemyName}");
                            enemy.Quest = quest;
                            playerController.AddQuest(quest);
                        }
                    }
                }
            }
        }
コード例 #23
0
        private IDictionary <string, NodeType> FindSubgraphAndMarkNodes(GraphType otherGraph)
        {
            IDictionary <string, IList <NodeType> > candidateMarkedNodes = new Dictionary <string, IList <NodeType> >();

            bool isSupergraphOfSourceGraph = SubgraphSearch(otherGraph, candidateMarkedNodes);

            if (!isSupergraphOfSourceGraph)
            {
                throw new InvalidOperationException($"No subgraph found in graph {id} matching source graph" +
                                                    $" {otherGraph.id}, so cannot carry out find and replace operation");
            }

            IDictionary <string, NodeType> markedNodes = new Dictionary <string, NodeType>(candidateMarkedNodes.Count);

            foreach (KeyValuePair <string, IList <NodeType> > keyValuePair in candidateMarkedNodes)
            {
                IList <NodeType> nodes     = keyValuePair.Value;
                NodeType         nodeToUse = nodes[nodes.Count == 1 ? 0 : Random.Range(0, nodes.Count)];
                markedNodes[keyValuePair.Key] = nodeToUse;
            }

            return(markedNodes);
        }
コード例 #24
0
 public abstract void Process(GraphType missionGraph, IDictionary <string, GameObject[]> generatedSpace);
コード例 #25
0
 public override void Process(GraphType missionGraph, IDictionary <string, GameObject[]> generatedSpace)
 {
     DestroyAttachedAttachmentPoints();
     AttachWallsToUnattachedAttachmentPoints(generatedSpace);
 }
コード例 #26
0
 public bool IsSupergraphOf(GraphType otherGraph)
 {
     return(HasAllSymbolsIn(otherGraph) && SubgraphSearch(otherGraph));
 }