/// <summary> /// determines which nodes exist on the right hand side of the grammar but not on the left hand and ads them to the translation table /// </summary> /// <param name="rule"></param> /// <param name="nodeGraph"></param> /// <param name="translationTable"></param> private static void AddMissingNodes(NodeGrammar rule, ref NodeGraph nodeGraph, ref OrderedDictionary <int, int> translationTable) { if (rule.RightHand.NodeDict.Count == 0) { return; } // we use the first node as a reference point to offset the positions var rightHandPosition = rule.RightHand.NodeDict.First().Value.Pos; var graphPosition = nodeGraph.NodeDict[translationTable.First().Value].Pos; // add all new nodes created by the rule and give them the proper index foreach (var rhNode in rule.RightHand.NodeDict) { // if the node exists on the right hand but no the left hand it's a missing node and we add it if (!rule.LeftHand.NodeDict.ContainsKey(rhNode.Key)) { var newNode = new Node() { Node_text = rhNode.Value.Node_text, Value = rhNode.Value.Value, Pos = graphPosition + rhNode.Value.Pos - rightHandPosition }; var newIndex = nodeGraph.AddNode(newNode); translationTable.Add(rhNode.Key, newIndex); } } }
private void SaveGrammar(int grammarIndex) { if (_grammars.Count < grammarIndex) { return; } _grammars[grammarIndex] = new NodeGrammar { Name = _grammars[grammarIndex].Name, LeftHand = _nodeEditorWindows[(int)HandSide.LEFT].Nodegraph, RightHand = _nodeEditorWindows[(int)HandSide.RIGHT].Nodegraph }; }
/// <summary> /// returns true if the grammar rule <paramref name="rule"/> has a left hand side that is a subgraph of <paramref name="nodeGraph"/>, /// </summary> /// <param name="rule">the rule containing the subgraph to match against</param> /// <param name="nodeGraph">the supergraph</param> /// <param name="translationTable">the IDs of the subgraph as they corrolate to IDs on the supergraph</param> /// <returns></returns> private static bool IsGrammarApplicable(NodeGrammar rule, ref NodeGraph nodeGraph, out OrderedDictionary <int, int> translationTable, int seed) { translationTable = null; var subgraphDict = rule.LeftHand.NodeDict; var firstSubgraphID = subgraphDict.Keys.Min(); // we brute force check all the nodes in the super graph to see if we can start inserting the subgraph there foreach (var superGraphNode in ShuffleDictionary(nodeGraph.NodeDict, seed)) { if (IsPlacementValid(new OrderedDictionary <int, int>(), firstSubgraphID, superGraphNode.Key, ref subgraphDict, nodeGraph.NodeDict, out OrderedDictionary <int, int> translation)) { translationTable = translation; return(true); } } return(false); }
/// <summary> /// applies a single node graph translation where a matching precept from the left hand side, found in the graph <paramref name="nodeGraph"/> is applied according to the <paramref name="nodeGraph"/> e.g. the tranlsation table has an entry [1,5] thus the node with ID 5 in <paramref name="nodeGraph"/> matches ID 1 in <paramref name="rule"/>.LeftHand and will thus be replace by the node linked to by ID 5 of <paramref name="rule"/>.RightHand /// </summary> /// <param name="rule"></param> /// <param name="nodeGraph"></param> /// <param name="translationTable"></param> private static void ApplyNodeRule(NodeGrammar rule, ref NodeGraph nodeGraph, ref OrderedDictionary <int, int> translationTable) { // nodes existing in the replacement but not in the translation table are added AddMissingNodes(rule, ref nodeGraph, ref translationTable); foreach (var translation in translationTable) { // the node that is to be transformed var node = nodeGraph.NodeDict[translation.Value]; // the Key indicates the LeftHand node that matched with this one, we thus want the matching righthand to replace it if (rule.RightHand.NodeDict.TryGetValue(translation.Key, out Node replacementNode)) { // * nodes won't have their values changed, only their connections are modified if (replacementNode.Node_text != "*") { node.Node_text = replacementNode.Node_text; node.Value = replacementNode.Value; } List <int> newConnections = new List <int>(); // maintain the connections this node had and translate them to the new IDs foreach (var connection in node.ConnectedNodes) { if (!translationTable.Values.Contains(connection)) { newConnections.Add(connection); } } // add new connections as described in the grammar foreach (var connection in replacementNode.ConnectedNodes) { if (translationTable.TryGetValue(connection, out int index)) { newConnections.Add(index); } } node.ConnectedNodes = newConnections; } else { // this node doesn't exist in the right hand thus is indicates a deletion nodeGraph.Delete(node); } } }
public void LoadMechanicGraph(int inputSeed = -1) { List <NodeGrammar> grammars = new List <NodeGrammar>(); foreach (var grammar in _nodeGrammars) { grammars.AddRange(NodeGrammar.ImportGrammars(Application.streamingAssetsPath + "/Grammar/Node/" + grammar + ".json")); } // generate a simple left hand side for now var inputGraph = new NodeGraph(); inputGraph.AddNode(new Node() { Node_text = "S" }); var seed = _randomString ? UnityEngine.Random.Range(0, 1000) : _seed; if (inputSeed != -1) { seed = inputSeed; } var stringgrams = GrammarUtils.ImportGrammars(Application.streamingAssetsPath + "/Grammar/String/" + _stringGrammar + ".json"); var inputString = GrammarUtils.ApplyGrammars(ref stringgrams, _inputString, seed); Debug.Log("mechanic generated with input string " + inputString); Debug.Log("Seed: " + seed); FindObjectOfType <SeedDisplay>()?.DisplaySeed(seed); _mechanicGraph = GrammarUtils.ApplyNodeGrammars(inputString, ref grammars, inputGraph, seed); AnalyseMechanicNodes(); AdjustBalance(); AnalyseMechanicNodes(); ApplySignifiers(); NodeBehaviour.Callbacks = new Stack <NodeActivationCallBack>(); NodeBehaviour.PlayerAttacks = GetComponent <PlayerAttackControl>(); NodeBehaviour.PlayerMovement = GetComponent <PlayerMovement>(); }
private void GrammarSaveAndLoad() { _exportName = EditorGUILayout.TextField("File Name : ", _exportName); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("import")) { _grammars = NodeGrammar.ImportGrammars(_directory + _exportName + ".json"); if (_grammars == default) { Reset(); } LoadGrammar(_grammarSelectedIndex); } if (GUILayout.Button("export")) { SaveGrammar(_grammarSelectedIndex); StreamWriter writer = new StreamWriter(_directory + _exportName + ".json"); var jsonString = SerializableNodeGrammars_Converter.ToJson(_grammars); writer.Write(jsonString); writer.Close(); writer.Dispose(); } EditorGUILayout.EndHorizontal(); }