// Simple function for setting the tree of the agent. // All trees are defined by their rootnode: N_Root. public void SetTree(N_Root treeRoot, N_AgentNode.AgentType agent) { btRoot = treeRoot; // Find all agentnodes and set their agent to be this one. List <Node> agentNodes = TreeOperations.RetrieveNodesOfType(treeRoot, typeof(N_AgentNode)); foreach (N_AgentNode n in agentNodes) { n.SetAgent(agent); } }
// Load both trees and assign them to the match simulator. private IEnumerator StartBattle() { singleBT = FileSaver.GetInstance().LoadTree(singleFilename); multiBT = FileSaver.GetInstance().LoadTree(multiFilename); // Reset scores m_singleWon = m_multiWon = 0; m_singleDamage = m_multiDamage = 0; m_singleHealth = m_multiHealth = 0; if (singleBT == null || multiBT == null) { Debug.LogError("Couldn't find requested behaviourtrees."); m_feedbackText.SetText("There doesn't exist a file for each algorithm. Please evolve using one of each before battling."); yield return(null); } originalMatchLength = m_simulator.matchTime; m_simulator.matchTime = matchLength; // Disable button canvas before starting simulation m_buttonCanvas.SetActive(false); for (int i = 0; i < simulationMatches; i++) { m_feedbackText.SetText("Battle " + i); // Start match and set timescale battleOn = true; m_simulator.liveSimulationScale = battleTimeScale; // Start match and wait until over. m_simulator.SetAgentBTs(singleBT, multiBT); m_simulator.StartMatch(); yield return(new WaitUntil(() => !battleOn)); } ScreenCapture.CaptureScreenshot("Resultat.png"); m_feedbackText.SetText("Single won: " + m_singleWon + ", Multi won: " + m_multiWon + "\n" + "Single damage: " + m_singleDamage + ", Multi damage: " + m_multiDamage + "\n" + "Single health: " + m_singleHealth + ", Multi health: " + m_multiHealth); m_buttonCanvas.SetActive(true); // Reset simulation scale and matchtime before yielding m_simulator.liveSimulationScale = m_simulator.simulationTimeScale; m_simulator.matchTime = originalMatchLength; yield return(null); }
public void SaveTree(N_Root tree, string fileName) { string filePath = directoryPath + "/" + fileName + ".tree"; if (!File.Exists(filePath)) { Directory.CreateDirectory(directoryPath); FileStream newFile = File.Create(filePath); newFile.Close(); } BinaryFormatter bf = new BinaryFormatter(); FileStream file = File.Open(filePath, FileMode.Create); bf.Serialize(file, tree); file.Close(); Debug.Log("Successfully saved " + filePath); }
// Randomize a new BT using given defined subtrees and definitions. protected Genome RandomGenome() { N_Root root = new N_Root(); Genome randomGenome = new Genome(); // First, randomize starting composition. N_CompositionNode firstComp = RandomComp(); N_CompositionNode currentComp = firstComp; bool nestled = false; // Generate random subtrees for (int i = 0; i < genomeSubtrees; i++) { // Calculate random chance for adding a new composition as well // as ending it. float randomChance = UnityEngine.Random.Range(0.0f, 1.0f); if (randomChance < additionalCompChance && !nestled) { nestled = true; N_CompositionNode subComp = RandomComp(); // Attach new composition and add a subtree to it. currentComp.AddLast(subComp); currentComp = subComp; } else if (randomChance < (additionalCompChance + 0.2f) && nestled) { nestled = false; currentComp = firstComp; } // Lastly, add a random subtree to the current composition as // well as to the list of subtree roots. Node subTree = RandomSubtree(); randomGenome.SubRoots.Add(subTree); currentComp.AddLast(subTree); } root.Child = firstComp; randomGenome.RootNode = root; return(randomGenome); }
public N_Root LoadTree(string fileName) { string filePath = directoryPath + "/" + fileName + ".tree"; if (File.Exists(filePath)) { BinaryFormatter bf = new BinaryFormatter(); FileStream file = File.Open(filePath, FileMode.Open); N_Root data = (N_Root)bf.Deserialize(file); file.Close(); Debug.Log("Successfully loaded " + filePath); return(data); } else { Debug.Log("No savefile found, when trying to load."); return(null); } }
public static List <Node> RetrieveNodesOfType(N_Root tree, Type nodeType) { Queue <Node> itQ = new Queue <Node>(); List <Node> found = new List <Node>(); itQ.Enqueue(tree.Child); // Do a breadth-first search to retrieve all nodes of the given type. while (itQ.Count > 0) { Node current = itQ.Dequeue(); // If the current node ís the same as the search type // or a subclass of it, add it to found. if (current.GetType().IsSubclassOf(nodeType) || current.GetType() == nodeType) { found.Add(current); } // If node is a composition or decorator, enqueue its child(ren). if (current.GetType().IsSubclassOf(typeof(N_CompositionNode))) { N_CompositionNode comp = current as N_CompositionNode; foreach (Node n in comp.GetChildren()) { itQ.Enqueue(n); } } else if (current.GetType().IsSubclassOf(typeof(N_Decorator))) { N_Decorator dec = current as N_Decorator; itQ.Enqueue(dec.Child); } } // Lastly, return the found children. return(found); }
// Return a list of all nodes that act as roots for a randomized subtree. public static List <Node> RetrieveSubtreeNodes(N_Root tree) { Queue <Node> itQ = new Queue <Node>(); List <Node> found = new List <Node>(); itQ.Enqueue(tree.Child); while (itQ.Count > 0) { Node current = itQ.Dequeue(); // If current node is flagged as subtree, add it to found if (current.IsSubtree) { found.Add(current); } // If node is a composition or decorator, enqueue its child(ren). if (current.GetType().IsSubclassOf(typeof(N_CompositionNode))) { N_CompositionNode comp = current as N_CompositionNode; foreach (Node n in comp.GetChildren()) { itQ.Enqueue(n); } } else if (current.GetType().IsSubclassOf(typeof(N_Decorator))) { N_Decorator dec = current as N_Decorator; itQ.Enqueue(dec.Child); } } // Return all nodes found with the subtree flag return(found); }
// Assign random mutations to the given tree. protected void Mutate(N_Root child) { // First, check if there'll be any mutation at all. float random = UnityEngine.Random.Range(0.0f, 1.0f); if (random < mutationRate) { List <Node> thresholds = TreeOperations.RetrieveNodesOfType(child, typeof(N_Threshold)); List <Node> probNodes = TreeOperations.RetrieveNodesOfType(child, typeof(N_ProbabilitySelector)); // Randomise between whether to change thresholds or probabilities random = UnityEngine.Random.Range(0.0f, 1.0f); // If no probnode exists, change condition if there are any instead if ((random <= 0.25f && thresholds.Count > 0)) { //Debug.Log("Changing threshold!"); // Get random index within range of list int index = UnityEngine.Random.Range(0, thresholds.Count); N_Threshold thresh = thresholds[index] as N_Threshold; // Mutate threshold by random offset int offset = UnityEngine.Random.Range(minThresholdOffset, maxTresholdOffset); thresh.SetThreshold(thresh.Threshold + offset); } else if (random > 0.25f && random <= 0.5f && probNodes.Count > 0) // Adjust relative probabilities on a probability selector. { //Debug.Log("Changing prob!"); // Get random index within range of list int index = UnityEngine.Random.Range(0, probNodes.Count); N_ProbabilitySelector probSelect = probNodes[index] as N_ProbabilitySelector; // Check so that the probablitySelector has any children. if (probSelect.GetChildren().Count <= 0) { return; } // Calculate total probability and retrieve a relative offset based on it. float totalProb = 0.0f; foreach (Node n in probSelect.GetChildren()) { totalProb += probSelect.GetProbabilityWeight(n); } float offset = totalProb * (relativeProbabilityMutation / 100.0f); // Also, get a random sign to decide whether to substract or add offset // and a random index for which child to be changed. float randomSign = Mathf.Sign(UnityEngine.Random.Range(-1.0f, 1.0f)); int randomChildIndex = UnityEngine.Random.Range(0, probSelect.GetChildren().Count); // Finally, offset the given childs probability by the random amount. probSelect.OffsetProbabilityWeight(probSelect.GetChildren()[randomChildIndex] , offset * randomSign); } else if (random > 0.5f && random <= 0.75f) // Change subtree { //Debug.Log("Changing subtree!"); List <Node> subtrees = TreeOperations.RetrieveSubtreeNodes(child); int randomIndex = UnityEngine.Random.Range(0, subtrees.Count); Node subtree = subtrees[randomIndex]; N_CompositionNode parentComp = subtree.Parent as N_CompositionNode; // Get a random subtree index and replace its position in the tree with // a new randomized subtree instead. parentComp.ReplaceChild(subtree, RandomSubtree()); } else if (random > 0.75f) // Change composition { //Debug.Log("Changing composition!"); List <Node> comps = TreeOperations.RetrieveNodesOfType(child, typeof(N_CompositionNode)); int randomIndex = UnityEngine.Random.Range(0, comps.Count); N_CompositionNode replaceComp = comps[randomIndex] as N_CompositionNode; // If parent is null, this comp is the initial comp. if (replaceComp.Parent != null) { Node compParent = replaceComp.Parent; List <Node> children = replaceComp.GetChildren(); // Attach old comps children to the new one. N_CompositionNode newComp = RandomComp(); // Make sure to keep structure of subtrees if (replaceComp.IsSubtree) { newComp.IsSubtree = true; } foreach (Node c in children) { c.Parent = newComp; newComp.AddLast(c); } // Reattach parent to the new comp if (compParent.GetType().IsSubclassOf(typeof(N_CompositionNode))) { N_CompositionNode compParent_comp = compParent as N_CompositionNode; compParent_comp.ReplaceChild(replaceComp, newComp); } else if (compParent.GetType().IsSubclassOf(typeof(N_Decorator))) { N_Decorator compParent_dec = compParent as N_Decorator; compParent_dec.Child = newComp; } } } } }
public Genome(N_Root root) { subRoots = new List <Node>(); rootNode = root; }
// Initialize variables. public Genome() { subRoots = new List <Node>(); rootNode = null; }
// Set the behaviour trees of the agents. public void SetAgentBTs(N_Root bt0, N_Root bt1) { bt_agent0.SetTree(bt0, N_AgentNode.AgentType.agent0); bt_agent1.SetTree(bt1, N_AgentNode.AgentType.agent1); }