/// <summary> /// Method is an entry point that controls the operation of the algorithm (the sequence of launching other methods). /// </summary> public void Start() { // We read the settings and create the initial state of the world. // ReadUserSettingsInput(); CreateInitialState(); CreateConstraints(); GenerateNewPDDLDomains(); // We create a start node (root) based on the start state of the world. StoryNode root = new StoryNode(); root.SetWorldState(currentStoryState); root.SetActivePlayer(false); root.SetActiveAgent(currentStoryState.GetFirstAgent()); newStoryGraph.SetRoot(root); // We go through all the agents and remember their goals. storyworldConvergence.ExtractGoals(currentStoryState); // The algorithm calculates a SPECIFIC story. newStoryGraph = CreateStoryGraph(newStoryGraph.GetRoot()); // Create a visual graph. graphСonstructor.CreateGraph(newStoryGraph, @"D:\Graphviz\bin\newStoryGraph.dt"); // Create an HTML file including Twine engine and generated history. //twineGraphConstructor.ConstructGraph(newStoryGraph); //twineGraphConstructor.CreateHTMLFileWithGame(); // SaveFile(); }
public void DuplicateNodeConnecting(WorldDynamic currentState, PlanAction action, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, StoryNode currentNode, int globalNodeNumber, ref Queue <StoryNode> queue, bool succsessControl, ref bool skip) { StoryNode testNode = CreateTestNode(currentState, action, agent, currentNode, false, globalNodeNumber, succsessControl); testNode.UpdateHashCode(); if (!testNode.Equals(currentNode)) { foreach (var checkedNode in nodes) { if (TwoNodesComparison(testNode, checkedNode) && !currentNode.ConnectedWith(checkedNode)) { DeleteTestNode(ref testNode); ConnectionTwoNodes(action, currentNode, checkedNode, true); break; } } } else { DeleteTestNode(ref testNode); skip = true; } }
public bool CyclesControl(WorldDynamic currentState, PlanAction action, StoryGraph currentGraph, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, StoryNode currentNode, bool duplicated, int globalNodeNumber, bool succsessControl) { bool result = false; // We create a test node similar to the one we are going to add to the graph as a result of the current action. StoryNode testNode = currentGraph.CreateTestNode(currentState, action, agent, currentNode, !duplicated, globalNodeNumber, succsessControl); StoryNode duplicatedNode = null; Edge testEdge = new Edge(); if (!duplicated) { duplicatedNode = currentGraph.GetNode(testNode); if (currentNode.Equals(duplicatedNode)) { return(false); } testEdge.SetUpperNode(ref currentNode); testEdge.SetLowerNode(ref duplicatedNode); currentNode.AddEdge(testEdge); duplicatedNode.AddEdge(testEdge); currentNode.AddLinkToNode(ref duplicatedNode); duplicatedNode.AddLinkToNode(ref currentNode); } string[] colors = new string[currentGraph.GetNodes().Count + 2]; for (int i = 0; i < currentGraph.GetNodes().Count + 2; i++) { colors[i] = "white"; } result = TarjanAlgStep(currentGraph.GetRoot(), ref colors, !duplicated, duplicatedNode); if (!duplicated) { currentNode.RemoveEdge(testEdge); currentNode.DeleteLink(duplicatedNode); duplicatedNode.RemoveEdge(testEdge); duplicatedNode.DeleteLink(currentNode); testEdge.ClearUpperNode(); testEdge.ClearLowerNode(); testEdge = null; } // We delete the test node and mark the loop test as passed. currentGraph.DeleteTestNode(ref testNode); return(result); }
/// <summary> /// The method that controls the creation of the history graph. /// </summary> public StoryGraph CreateStoryGraph(StoryNode rootNode) { // We clone the root into a separate variable. StoryNode originRoot = (StoryNode)rootNode.Clone(); // We continue to work until at least one target state is reached. while (!reachedGoalState) { // We create a new graph by starting to expand the root. BFSTraversing(newStoryGraph.GetRoot()); // We go through the created graph, looking for target states in it. BFSGoalAchieveControl(newStoryGraph.GetRoot()); // If it was not possible to find even one target state in the constructed graph. if (!reachedGoalState || newStoryGraph.GetNodes().Count > maxNodes) { graphСonstructor.CreateGraph(newStoryGraph, @"D:\Graphviz\bin\newStoryGraph.dt"); // Then we clear the graph, and all the links added to the root. newStoryGraph = new StoryGraph(); originRoot.GetEdges().Clear(); originRoot.GetLinks().Clear(); // After that, we reassign to the previously cleared column an indication of the root. newStoryGraph.SetRoot((StoryNode)originRoot.Clone()); reachedGoalState = false; } } // We return a graph that is guaranteed to have at least one target state. return(newStoryGraph); }
public bool DuplicateControl(WorldDynamic currentState, PlanAction action, StoryGraph currentGraph, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, StoryNode currentNode, int globalNodeNumber, bool succsessControl) { StoryNode testNode = currentGraph.CreateTestNode(currentState, action, agent, currentNode, false, globalNodeNumber, succsessControl); testNode.UpdateHashCode(); foreach (var checkedNode in currentGraph.GetNodes()) { checkedNode.UpdateHashCode(); if (currentGraph.TwoNodesComparison(testNode, checkedNode)) { currentGraph.DeleteTestNode(ref testNode); return(false); } } currentGraph.DeleteTestNode(ref testNode); return(true); }
public void MultiAVandAC(ref PlanAction receivedAction, WorldDynamic currentState, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, CSP_Module cspModule, StoryGraph currentGraph, StoryNode currentNode, bool root, ref int globalNodeNumber, ref Queue <StoryNode> queue) { List <PlanAction> actionsList = cspModule.MassiveAssignVariables(ref receivedAction, currentState, agent); AgentStateStatic sCurrentAgent = (AgentStateStatic)agent.Key.Clone(); AgentStateDynamic dCurrentAgent = (AgentStateDynamic)agent.Value.Clone(); KeyValuePair <AgentStateStatic, AgentStateDynamic> currentAgent = new KeyValuePair <AgentStateStatic, AgentStateDynamic>(sCurrentAgent, dCurrentAgent); WorldDynamic statePrefab = (WorldDynamic)currentState.Clone(); foreach (var a in actionsList) { ActionControl(a, currentGraph, currentAgent, statePrefab, currentNode, root, ref globalNodeNumber, ref queue); } // Cleaning actionsList = null; currentNode = null; statePrefab = null; GC.Collect(); }
public void CounterreactionControl(PlanAction action, StoryGraph currentGraph, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, WorldDynamic currentState, StoryNode currentNode, bool root, ref int globalNodeNumber, ref Queue <StoryNode> queue, ref bool controlOne, ref bool controlTwo) { bool succsessControl = ProbabilityCalculating(action); action.success = succsessControl; action.fail = !succsessControl; bool constraintsControl = ConstraintsControl(currentState, action, succsessControl); bool deadEndsControl = DeadEndsControl(action, currentState, agent, succsessControl); bool duplicateControl = DuplicateControl(currentState, action, currentGraph, agent, currentNode, globalNodeNumber, succsessControl); //bool cyclesControl = CyclesControl(currentState, action, currentGraph, agent, currentNode, duplicateControl, globalNodeNumber, succsessControl); bool cyclesControl = true; controlOne = constraintsControl & deadEndsControl & cyclesControl; controlTwo = duplicateControl; }
public bool TwoNodesComparison(StoryNode nodeOne, StoryNode nodeTwo) { if (nodeOne.Equals(nodeTwo)) { return(true); } return(false); }
public void ClearLowerNode() { if (lowerNode != null) { lowerNode.GetEdges().Remove(this); lowerNode = null; } }
/// <summary> /// Create a new node for the story graph and inserts it. /// </summary> public void CreateNewNode(PlanAction action, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, WorldDynamic currentState, StoryNode currentNode, ref int globalNodeNumber, bool succsessControl, bool counteract) { WorldDynamic newState = (WorldDynamic)currentState.Clone(); if (!succsessControl) { action.Fail(ref newState); } else { action.ApplyEffects(ref newState); } newState.UpdateHashCode(); // Create an empty new node. StoryNode newNode = new StoryNode(); if (counteract) { newNode.counteract = true; } // We assign the state of the world (transferred) to the new node. newNode.SetWorldState((WorldDynamic)newState.Clone()); newNode.SetActiveAgent(newNode.GetWorldState().GetAgentByName(agent.Key.GetName())); if (agent.Key.GetRole() == AgentRole.PLAYER) { newNode.SetActivePlayer(true); } else { newNode.SetActivePlayer(false); } ConnectionTwoNodes(action, currentNode, newNode, false); globalNodeNumber++; newNode.SetNumberInSequence(globalNodeNumber); if (nodes.Contains(newNode)) { bool test = true; } // Add a new node to the graph. AddNode(newNode); }
public StoryNode GetNode(StoryNode node) { foreach (var n in nodes) { if (node.Equals(n)) { return(n); } } throw new KeyNotFoundException(); }
public bool TarjanAlgStep(StoryNode checkedNode, ref string[] colors, bool duplicated, StoryNode duplicatedNode) { bool result = true; colors[checkedNode.GetNumberInSequence()] = "grey"; foreach (StoryNode nextNode in checkedNode.GetLinks()) { if (!result) { return(result); } if (colors[nextNode.GetNumberInSequence()] == "grey") { if (duplicated) { if (duplicatedNode.Equals(nextNode)) { bool test = true; } } if (checkedNode.isChildren(nextNode) && !duplicated) { continue; } else if (duplicated && checkedNode.isChildren(nextNode) && !duplicatedNode.Equals(nextNode)) { continue; } result = false; return(result); } else if (colors[nextNode.GetNumberInSequence()] == "black") { continue; } else { result = TarjanAlgStep(nextNode, ref colors, duplicated, duplicatedNode); if (!result) { return(result); } } } colors[checkedNode.GetNumberInSequence()] = "black"; return(result); }
public bool NodeExistenceControl(StoryNode checkedNode) { foreach (var node in GetNodes()) { if (TwoNodesComparison(node, checkedNode)) { return(true); } } return(false); }
public StoryNode CreateTestNode(WorldDynamic currentState, PlanAction action, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, StoryNode currentNode, bool connection, int globalNodeNumber, bool succsessControl) { WorldDynamic worldForTest = (WorldDynamic)currentState.Clone(); if (!succsessControl) { action.Fail(ref worldForTest); } else { action.ApplyEffects(ref worldForTest); } worldForTest.UpdateHashCode(); StoryNode testNode = new StoryNode(); //if (counteract) { testNode.counteract = true; } //testNode.SetWorldState(worldForTest); testNode.SetWorldState((WorldDynamic)worldForTest.Clone()); // Create a clone of the agent. //KeyValuePair<AgentStateStatic, AgentStateDynamic> newAgent = // new KeyValuePair<AgentStateStatic, AgentStateDynamic>((AgentStateStatic)agent.Key.Clone(), (AgentStateDynamic)agent.Value.Clone()); testNode.SetActiveAgent(testNode.GetWorldState().GetAgentByName(agent.Key.GetName())); // We take the last node from the list of all nodes and assign whether the player is active and which of the agents was active on this turn. if (agent.Key.GetRole() == AgentRole.PLAYER) { testNode.SetActivePlayer(true); } else { testNode.SetActivePlayer(false); } //testNode.SetActiveAgent(newAgent); /*if (connection) * { * ConnectionTwoNodes(action, currentNode, testNode, false); * }*/ testNode.SetNumberInSequence(globalNodeNumber + 1); return(testNode); }
/// <summary> /// Checks the achievement of any of the goal conditions (in state). /// </summary> /// <param name="currentWorldState"></param> public bool ControlToAchieveGoalState(ref StoryNode currentNode) { foreach (var goal in allGoalStates) { // todo: convert to switch // todo: supplement the types of goals - group and specific if (goal.goalTypeIsStatus) { int killCounter = 0; bool killerDied = false; foreach (var agent in currentNode.GetWorldState().GetAgents()) { switch (agent.Key.GetRole()) { case AgentRole.USUAL: if (!agent.Value.GetStatus()) { killCounter++; } break; case AgentRole.PLAYER: if (!agent.Value.GetStatus()) { killCounter++; } break; case AgentRole.KILLER: if (!agent.Value.GetStatus()) { killerDied = true; } break; } } if (killCounter == currentNode.GetWorldState().GetAgents().Count - 1) { currentNode.goalState = true; return(true); } if (killerDied) { currentNode.goalState = true; return(true); } } } return(false); }
/// <summary> /// Checking the action for violation of the established constraints and the reachability of the goal state (control of cycles and deadends). /// </summary> public void ActionControl(PlanAction action, StoryGraph currentGraph, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, WorldDynamic currentState, StoryNode currentNode, bool root, ref int globalNodeNumber, ref Queue <StoryNode> queue) { bool succsessControl = ProbabilityCalculating(action); action.success = succsessControl; action.fail = !succsessControl; bool constraintsControl = ConstraintsControl(currentState, action, succsessControl); bool deadEndsControl = DeadEndsControl(action, currentState, agent, succsessControl); bool duplicateControl = DuplicateControl(currentState, action, currentGraph, agent, currentNode, globalNodeNumber, succsessControl); //bool cyclesControl = CyclesControl(currentState, action, currentGraph, agent, currentNode, duplicateControl, globalNodeNumber, succsessControl); bool cyclesControl = true; if (constraintsControl && deadEndsControl && cyclesControl && duplicateControl) { // If all checks are passed, then we apply the action. ApplyAction(action, currentGraph, agent, currentState, currentNode, root, ref globalNodeNumber, succsessControl, false); } else if (!constraintsControl && deadEndsControl && cyclesControl && duplicateControl) { // If the action violates the constraints, then convergence will not apply it, but will apply its counter-reaction. ActionCounteract(action, currentGraph, agent, currentState, currentNode, root, ref globalNodeNumber, ref queue); } else if (!duplicateControl && cyclesControl) { bool skip = false; // connection current node --> finded node currentGraph.DuplicateNodeConnecting(currentState, action, agent, currentNode, globalNodeNumber, ref queue, succsessControl, ref skip); if (skip) { //NothingToDo newAction = new NothingToDo(); //newAction.Arguments.Add(agent); //ApplyAction(newAction, currentGraph, agent, currentState, currentNode, root, ref globalNodeNumber, succsessControl, true); ActionCounteract(action, currentGraph, agent, currentState, currentNode, root, ref globalNodeNumber, ref queue); } } else { ActionCounteract(action, currentGraph, agent, currentState, currentNode, root, ref globalNodeNumber, ref queue); } }
public void DeleteTestNode(ref StoryNode testNode) { foreach (var edge in testNode.GetEdges().ToList()) { edge.GetUpperNode().RemoveEdge(edge); edge.GetLowerNode().RemoveEdge(edge); edge.ClearEdge(); } foreach (var link in testNode.GetLinks().ToList()) { testNode.DeleteLink(link); } }
public void SingleAVandAC(ref PlanAction receivedAction, WorldDynamic currentState, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, CSP_Module cspModule, StoryGraph currentGraph, StoryNode currentNode, bool root, ref int globalNodeNumber, ref Queue <StoryNode> queue) { cspModule.AssignVariables(ref receivedAction, currentState, agent); ActionControl(receivedAction, currentGraph, agent, currentState, currentNode, root, ref globalNodeNumber, ref queue); // Cleaning currentNode = null; GC.Collect(); }
/// <summary> /// Convergence in turn asks agents for actions, checks them, applies them, counteracts them, or does not. /// </summary> public void Step(StoryNode currentNode, int agentIndex, bool root, ref int globalNodeNumber, ref Queue <StoryNode> queue) { // Convergence assigns who is on the turn to the node and then applies the changes to the state of the world. currentStoryState = currentNode.GetWorldState(); currentStoryState.GetStaticWorldPart().IncreaseTurnNumber(); while (!currentStoryState.GetAgentByIndex(agentIndex).Value.GetStatus()) { agentIndex = GetActualAgentNumber(agentIndex, ref currentNode); } // We check if the agent from whom we are going to request an action is alive (i.e. capable of doing it). if (currentStoryState.GetAgentByIndex(agentIndex).Value.GetStatus()) { // We create a request for action of the specified agent from the specified state. storyworldConvergence.ActionRequest(currentStoryState.GetAgentByIndex(agentIndex), ref newStoryGraph, ref currentStoryState, currentNode, root, ref globalNodeNumber, ref queue); } }
/// <summary> /// A method that traverses the graph according to the concept of breadth-first search /// and determines the presence of at least one target state in it. /// </summary> public bool BFSGoalAchieveControl(StoryNode rootNode) { // We create a queue and a list of visited nodes. Queue <StoryNode> queue = new Queue <StoryNode>(); HashSet <StoryNode> visitedNodes = new HashSet <StoryNode>(); // Add the root node to the queue and the list of visited nodes. queue.Enqueue(rootNode); visitedNodes.Add(rootNode); // We are in a loop until the queue is empty. while (queue.Count > 0) { // We take the current node under consideration from the queue. StoryNode currentNode = queue.Dequeue(); // We check if the target state has been reached in the node under consideration. reachedGoalState = storyworldConvergence.ControlToAchieveGoalState(ref currentNode); // If so, terminate the method and return true. if (reachedGoalState) { return(true); } // Otherwise, we go through the nodes associated with the node in question. foreach (StoryNode nextNode in currentNode.GetLinks()) { // If they have already been visited earlier, then we continue, moving on to the next. if (visitedNodes.Contains(nextNode)) { continue; } // Otherwise, we add to the queue and the list of visited nodes. queue.Enqueue(nextNode); visitedNodes.Add(nextNode); } } // If no target state was found, then terminate the method and return false. return(false); }
/// <summary> /// The probability of success of the action is calculated, and if successful, it is applied. /// </summary> public void ApplyAction(PlanAction action, StoryGraph currentGraph, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, WorldDynamic currentState, StoryNode currentNode, bool root, ref int globalNodeNumber, bool succsessControl, bool counteract) { // We apply a successful/unsuccessful option to perform an action. if (root) { currentGraph.CreateRootNode(action, agent, currentState, currentNode, ref globalNodeNumber, succsessControl); } else { currentGraph.CreateNewNode(action, agent, currentState, currentNode, ref globalNodeNumber, succsessControl, counteract); } }
/// <summary> /// /// </summary> /// <param name="firstNode">Current node</param> /// <param name="secondNode">New node</param> public void ConnectionTwoNodes(PlanAction action, StoryNode firstNode, StoryNode secondNode, bool duplicate) { Edge newEdge = new Edge(); newEdge.SetAction(action); newEdge.SetUpperNode(ref firstNode); newEdge.SetLowerNode(ref secondNode); firstNode.AddEdge(newEdge); secondNode.AddEdge(newEdge); firstNode.AddLinkToNode(ref secondNode); secondNode.AddLinkToNode(ref firstNode); if (firstNode.GetEdges().Count != firstNode.GetLinks().Count) { bool test = true; } }
/// <summary> /// A method that returns the index of the agent that should perform the action. /// </summary> /// <param name="prevNumber">Index of the agent who performed the action in the previous state.</param> public int GetActualAgentNumber(int prevNumber, ref StoryNode currentNode) { // Flag for checking if the agent being checked is alive. bool aliveControl = false; // Determine how many agents exist in the current state. int maxNumber = currentNode.GetWorldState().GetNumberOfAgents(); // Default result. int result = 0; // Until the flag signaling the status of the agent being checked is omitted. while (!aliveControl) { // If the index of the previous agent is equal to the maximum possible index. if (prevNumber == maxNumber - 1) { // Then we go back to the beginning of the index list and set 0 as the result (the circle is passed). result = 0; prevNumber = 0; } else { // Otherwise, we increase the value of the index of the previous agent by one and write it down as a result. prevNumber++; result = prevNumber; } // We check if the agent with the received index is alive. If not, we continue the cycle. if (!currentNode.GetWorldState().GetAgentByIndex(result).Value.GetStatus()) { continue; } // Otherwise, we raise the flag that the control has been passed. aliveControl = true; } // We return the result - the index of the guaranteed living agent acting after the specified in the parameters. return(result); }
public void CreateRootNode(PlanAction action, KeyValuePair <AgentStateStatic, AgentStateDynamic> agent, WorldDynamic currentState, StoryNode currentNode, ref int globalNodeNumber, bool succsessControl) { WorldDynamic newState = (WorldDynamic)currentState.Clone(); if (!succsessControl) { action.Fail(ref newState); } else { action.ApplyEffects(ref newState); } if (agent.Key.GetRole() == AgentRole.PLAYER) { currentNode.SetActivePlayer(true); } else { currentNode.SetActivePlayer(false); } // We assign the state of the world (transferred) to the new node. currentNode.SetWorldState((WorldDynamic)newState.Clone()); //Edge newEdge = new Edge(); // We adjust the edge - assign its action and indicate the nodes that it connects. //newEdge.SetAction(action); //newEdge.SetUpperNode(ref currentNode); //currentNode.AddEdge(newEdge); globalNodeNumber++; currentNode.SetNumberInSequence(globalNodeNumber); }
/// <summary> /// A method in which we sequentially create a story graph, node by node, starting at the root, using the concept of Breadth First Search. /// </summary> public void BFSTraversing(StoryNode rootNode, bool root = true) { // We create a queue and a list of visited nodes. Queue <StoryNode> queue = new Queue <StoryNode>(); HashSet <StoryNode> visitedNodes = new HashSet <StoryNode>(); // Добавляем узел в очередь и список посещённых узлов. queue.Enqueue(rootNode); visitedNodes.Add(rootNode); // We initialize numeric variables storing the number of the current agent and the number of the last node in the sequence. int actualAgentNumber = 0; int globalNodeNumber = -1; // We will perform the action in a loop until the queue becomes empty. while (queue.Count > 0 && newStoryGraph.GetNodes().Count <= maxNodes) { // We take the node in question from the queue. StoryNode currentNode = queue.Dequeue(); // If we come across a node with a target state, then we do not expand it. if (storyworldConvergence.ControlToAchieveGoalState(ref currentNode)) { //currentNode.goalState = true; continue; } else { // If the node in question is a root. if (currentNode.Equals(rootNode) && root) { // We call the method for creating a new node. Step(newStoryGraph.GetRoot(), actualAgentNumber, root, ref globalNodeNumber, ref queue); // Add the considered node back to the queue (in the case of the root, we only changed it and will consider it again), // and also to the list of visited nodes. We remove the flag indicating that we are considering the root node. queue.Enqueue(currentNode); visitedNodes.Add(currentNode); root = false; } // If the node in question IS NOT a root. else { // We determine the index of the agent, which will have to act when creating a new node. actualAgentNumber = GetActualAgentNumber(currentNode.GetWorldState().GetIndexOfAgent(currentNode.GetActiveAgent()), ref currentNode); // We call the method to create a new node. Step(newStoryGraph.GetNode(currentNode), actualAgentNumber, root, ref globalNodeNumber, ref queue); } } // We go through the nodes associated with the considered one. foreach (StoryNode nextNode in currentNode.GetLinks()) { // If one of them has already been visited earlier, then we continue, moving on to the next. if (visitedNodes.Contains(nextNode)) { continue; } // Otherwise, we add them to the queue and the list of visited nodes. queue.Enqueue(nextNode); visitedNodes.Add(nextNode); } // We clear the link pointing to the node in question. currentNode = null; } }
public void SetLowerNode(ref StoryNode node) { lowerNode = node; }
/// <summary> /// Constructor method for story graph, no parameters. /// </summary> public StoryGraph() { root = new StoryNode(); nodes = new HashSet <StoryNode>(); }
public void SetRoot(StoryNode newRoot) { root = newRoot; AddNode(newRoot); }
public bool FindNode(StoryNode node) { return(nodes.Contains(node)); }
/// <summary> /// Adds a node to the list of nodes in the story graph. /// </summary> /// <param name="newNode"></param> public void AddNode(StoryNode newNode) { nodes.Add(newNode); }