// --------------------------------------- Reset methods --------------------------------------- public override void DestroyAndReset() { base.DestroyAndReset(); chosenNodes = 0; numberOfNodesToChoose = 0; // Variable reset backtracking = false; userTestGoalActive = false; usingCalculator = false; // Delete list visual listVisual.DestroyAndReset(); updateListVisualInstruction = null; // Delete graph graphManager.DeleteGraph(); // Reset algorithm graphAlgorithm.ResetSetup(); // Pseudocode pseudoCodeViewer.DestroyContent(); // Pointer pointer.ResetPointer(); StartCoroutine(ActivateTaskObjects(false)); calculator.ResetDevice(); demoDevice.ResetDevice(); }
private IEnumerator RecursiveDFS(Node currentNode) { // Line 4: Pop node from stack currentNode.Traversed = true; ListVisualInstruction removeCurrentNode = new ListVisualInstruction(UtilGraph.REMOVE_CURRENT_NODE, instNr, currentNode, 0); recursiveInstructions.Add(instNr, new TraverseInstruction(UtilGraph.POP_INST, instNr++, currentNode, currentNode.PrevEdge, false, true, removeCurrentNode)); for (int i = 0; i < currentNode.Edges.Count; i++) { Edge connectedEdge = currentNode.Edges[i]; Node connectedNode = connectedEdge.OtherNodeConnected(currentNode); // Line 6: If statement (condition) recursiveInstructions.Add(instNr, new TraverseInstruction(UtilGraph.IF_NOT_VISITED_INST, instNr++, connectedNode, connectedEdge, false, false)); if (!connectedNode.Visited) { connectedNode.PrevEdge = connectedEdge; // Line 7: Push node on top of stack ListVisualInstruction addConnectedNode = new ListVisualInstruction(UtilGraph.ADD_NODE, instNr, connectedNode); recursiveInstructions.Add(instNr, new TraverseInstruction(UtilGraph.PUSH_INST, instNr++, connectedNode, connectedEdge, true, false, addConnectedNode)); connectedNode.Visited = true; // Line 9: End for-loop (comment out the next line to see the order of all the nodes traversed - not as planned, but kinda useful) recursiveInstructions.Add(instNr, new TraverseInstruction(UtilGraph.END_FOR_LOOP_INST, instNr++, currentNode, false, false)); // <-- instructions.Add(instNr++, new ListVisualInstruction(UtilGraph.DESTROY_CURRENT_NODE, instNr, currentNode)); yield return(RecursiveDFS(connectedNode)); } // Line 8: End if statement //recursiveInstructions.Add(instNr++, new TraverseInstruction(UtilGraph.END_IF_INST, instNr, connectedNode, edge, false, false)); } // Line 9: End for-loop //recursiveInstructions.Add(instNr++, new TraverseInstruction(UtilGraph.END_FOR_LOOP_INST, instNr, currentNode, false, false)); // <-- instructions.Add(instNr++, new ListVisualInstruction(UtilGraph.DESTROY_CURRENT_NODE, instNr, currentNode)); }
public TraverseInstruction(string instruction, int instructionNr, Node node, bool visitInst, bool traverseInst, ListVisualInstruction listVisualInstruction) : base(instruction, instructionNr) { this.node = node; this.visitInst = visitInst; this.traverseInst = traverseInst; this.listVisualInstruction = listVisualInstruction; }
public ShortestPathInstruction(string instruction, int instructionNr, Node currentNode, Node connectedNode, Edge currentEdge, ListVisualInstruction listVisualInstruction) : base(instruction, instructionNr) { this.currentNode = currentNode; this.connectedNode = connectedNode; this.currentEdge = currentEdge; connectedNodeOldDist = connectedNode.Dist; connectedNodeNewDist = CurrentNode.Dist + currentEdge.Cost; this.listVisualInstruction = listVisualInstruction; }
public ShortestPathInstruction(string instruction, int instructionNr, Node connectedNode, Edge prevEdge, ListVisualInstruction listVisualInstruction) : base(instruction, instructionNr) { this.connectedNode = connectedNode; if (connectedNode.PrevEdge != null) { oldPrevEdge = connectedNode.PrevEdge; } this.prevEdge = prevEdge; this.listVisualInstruction = listVisualInstruction; }
// User test backtracking public void ShortestPatBacktrackingInstructions(Dictionary <int, InstructionBase> instructions, int instNr) { // Start backtracking from end node back to start node Node node = EndNode; instructions.Add(instNr, new InstructionBase(UtilGraph.MARK_END_NODE, instNr++)); // Fix list visual instructions.Add(instNr, new ListVisualInstruction(UtilGraph.PREPARE_BACKTRACKING, instNr++, node)); // Prepares backtracking list + moving current (end) node out of list // Set current node (remove from list) instructions.Add(instNr, new ListVisualInstruction(UtilGraph.BACKTRACK_REMOVE_CURRENT_NODE, instNr++, node)); while (node != null) { // Backtrack by using each node's prevEdge Edge backtrackEdge = node.PrevEdge; // Stop when we reach the start node if (backtrackEdge == null) { break; } // Set "next" node if (backtrackEdge is DirectedEdge) { ((DirectedEdge)backtrackEdge).PathBothWaysActive = true; } // Set the next node via the prevEdge node = backtrackEdge.OtherNodeConnected(node); // Add instruction for traversing + list visual ListVisualInstruction removeCurrentNodeRep = new ListVisualInstruction(UtilGraph.BACKTRACK_REMOVE_CURRENT_NODE, instNr, node, backtrackEdge); instructions.Add(instNr, new TraverseInstruction(UtilGraph.BACKTRACK, instNr++, node, false, true, removeCurrentNodeRep)); if (backtrackEdge is DirectedEdge) { ((DirectedEdge)backtrackEdge).PathBothWaysActive = false; // incase using same graph again at some point } //// Destroy node rep //instructions.Add(instNr++, new ListVisualInstruction(UtilGraph.DESTROY_CURRENT_NODE, instNr)); } instructions.Add(instNr, new ListVisualInstruction(UtilGraph.DESTROY_CURRENT_NODE, instNr++)); instructions.Add(instNr, new InstructionBase(Util.FINAL_INSTRUCTION, instNr++)); }
public Dictionary <int, InstructionBase> RecursiveInstructions(Node startNode) { Debug.Log("Preparing for recursive instruction farming"); recursiveInstructions = new Dictionary <int, InstructionBase>(); instNr = 0; // Line 0: Update start node recursiveInstructions.Add(instNr, new TraverseInstruction(Util.FIRST_INSTRUCTION, instNr++, startNode, false, false)); // Line 2: Push start node startNode.Visited = true; ListVisualInstruction addStartNode = new ListVisualInstruction(UtilGraph.ADD_NODE, instNr, startNode); recursiveInstructions.Add(instNr, new TraverseInstruction(UtilGraph.PUSH_INST, instNr++, startNode, true, false, addStartNode)); Debug.Log("Starting recursive instruction farming"); StartCoroutine(RecursiveDFS(startNode)); // Line 10: End while-loop //recursiveInstructions.Add(instNr++, new InstructionBase(UtilGraph.END_WHILE_INST, instNr)); return(recursiveInstructions); }
// Instructions from the New Demo/Step-by-step public void ExecuteInstruction(ListVisualInstruction instruction, bool increment) { switch (instruction.Instruction) { case UtilGraph.ADD_NODE: if (increment) { AddListObject(instruction.Node); } else { // Reverse of adding: Find node, remove it from the list, and destroy it NodeRepresentation nodeRep = FindNodeRepresentation(instruction.Node); if (nodeRep != null) { nodeRepresentations.Remove(nodeRep); Destroy(nodeRep.gameObject); } } break; case UtilGraph.PRIORITY_ADD_NODE: if (increment) { PriorityAdd(instruction.Node, instruction.Index); } else { NodeRepresentation nodeRep = FindNodeRepresentation(instruction.Node); nodeRepresentations.Remove(nodeRep); Destroy(nodeRep.gameObject); // Fix other indexes???? } break; case UtilGraph.REMOVE_CURRENT_NODE: if (increment) { RemoveCurrentNode(); } else { // Reverse of removing current node: insert and move it back into the list currentNode.CurrentColor = Color.white; graphMain.WaitForSupportToComplete++; switch (listType) { case Util.QUEUE: nodeRepresentations.Insert(0, currentNode); currentNode.ListIndex = 0; StartCoroutine(ReverseRemoveCurrentNode(currentNode, true)); break; case Util.STACK: nodeRepresentations.Add(currentNode); currentNode.ListIndex = nodeRepresentations.Count - 1; StartCoroutine(ReverseRemoveCurrentNode(currentNode, false)); break; case Util.PRIORITY_LIST: nodeRepresentations.Insert(0, currentNode); currentNode.ListIndex = instruction.Index; StartCoroutine(ReverseRemoveCurrentNode(currentNode, true)); break; } } break; case UtilGraph.DESTROY_CURRENT_NODE: if (increment) { DestroyCurrentNode(); } else { // Reverse of destroying: Instantiate a new one and place it in the current node spot currentNode = CreateNodeRepresentation(instruction.Node, currentNodePoint.position, -1); currentNode.CurrentColor = UtilGraph.TRAVERSE_COLOR; } break; case UtilGraph.SET_START_NODE_DIST_TO_ZERO: if (!increment) { instruction.Node.Dist = UtilGraph.INF; } FindNodeRepresentation(instruction.Node).UpdateSurfaceText(UtilGraph.DIST_UPDATE_COLOR); break; case UtilGraph.HAS_NODE_REPRESENTATION: /* This case has two outcomes: * 1) If the node doesn't have any node representations in the current list, then create and add a new one * 2) There is currently a node representation, so update this one */ Node node = instruction.Node; int index = instruction.Index; if (increment) { instruction.HasNodeRepresentation = HasNodeRepresentation(node); } if (!instruction.HasNodeRepresentation) // Case 1 { if (increment) { PriorityAdd(node, index); } else { ExecuteInstruction(new ListVisualInstruction(UtilGraph.PRIORITY_ADD_NODE, instruction.InstructionNr, node), false); } } else // Case 2 { if (increment) { graphMain.WaitForSupportToComplete++; StartCoroutine(UpdateValueAndPositionOf(node, index, increment)); } } break; case UtilGraph.END_NODE_FOUND: // Start backtracking if (increment) { graphMain.GetTeachingAlgorithm().PseudoCodeViewer.DestroyContent(); } else { graphMain.GetTeachingAlgorithm().PseudoCodeViewer.PseudoCodeSetup(); } break; case UtilGraph.PREPARE_BACKTRACKING: if (increment) { CreateBackTrackList(instruction.Node); //RemoveCurrentNode(); } else { Debug.Log("Nein...."); } break; case UtilGraph.BACKTRACK_REMOVE_CURRENT_NODE: if (increment) { DestroyCurrentNode(); RemoveCurrentNode(); if (graphMain.Settings.Difficulty < Util.EXAMINATION) { instruction.Node.CurrentColor = UtilGraph.SHORTEST_PATH_COLOR; if (instruction.BacktrackEdge != null) { instruction.BacktrackEdge.CurrentColor = UtilGraph.SHORTEST_PATH_COLOR; } } } else { instruction.Node.CurrentColor = UtilGraph.TRAVERSED_COLOR; if (instruction.BacktrackEdge != null) { instruction.BacktrackEdge.CurrentColor = UtilGraph.VISITED_COLOR; } ExecuteInstruction(new ListVisualInstruction(UtilGraph.REMOVE_CURRENT_NODE, Util.NO_INSTRUCTION_NR), false); } break; default: Debug.Log("List visual instruction '" + instruction.Instruction + "' invalid."); break; } timeForDebugUpdate = true; }
public Dictionary <int, InstructionBase> TraverseUserTestInstructions(Node startNode) { Dictionary <int, InstructionBase> instructions = new Dictionary <int, InstructionBase>(); int instNr = 0; // Line 0: Update start node instructions.Add(instNr, new TraverseInstruction(Util.FIRST_INSTRUCTION, instNr++, startNode, false, false)); // Line 1: Create emtpy list (queue) Queue <Node> queue = new Queue <Node>(); instructions.Add(instNr, new InstructionBase(UtilGraph.EMPTY_LIST_CONTAINER, instNr++)); // Line 2: Enqueue first node queue.Enqueue(startNode); startNode.Visited = true; ListVisualInstruction addStartNode = new ListVisualInstruction(UtilGraph.ADD_NODE, instNr, startNode); instructions.Add(instNr, new TraverseInstruction(UtilGraph.ENQUEUE_NODE_INST, instNr++, startNode, true, false, addStartNode)); while (queue.Count > 0) { // Line 4: While loop instructions.Add(instNr, new InstructionLoop(UtilGraph.WHILE_LIST_NOT_EMPTY_INST, instNr++, queue.Count)); // Line 5: Dequeue node Node currentNode = queue.Dequeue(); currentNode.Traversed = true; ListVisualInstruction removeCurrentNode = new ListVisualInstruction(UtilGraph.REMOVE_CURRENT_NODE, instNr, currentNode, 0); instructions.Add(instNr, new TraverseInstruction(UtilGraph.DEQUEUE_NODE_INST, instNr++, currentNode, currentNode.PrevEdge, false, true, removeCurrentNode)); // Go through each edge connected to current node // Line 6: For-loop update instructions.Add(instNr, new TraverseInstruction(UtilGraph.FOR_ALL_NEIGHBORS_INST, instNr++, currentNode, false, false)); //new InstructionLoop(UtilGraph.FOR_ALL_NEIGHBORS_INST, instNr, i, currentNode.Edges.Count, Util.NO_INDEX_VALUE)); for (int i = 0; i < currentNode.Edges.Count; i++) { Edge edge = currentNode.Edges[i]; Node connectedNode = edge.OtherNodeConnected(currentNode); // No need to check the edge we came from if (edge == currentNode.PrevEdge) { continue; } // Optimizing check //if (connectedNode.Visited || connectedNode.Traversed) // continue; // Line 7: check neighbor instructions.Add(instNr, new TraverseInstruction(UtilGraph.IF_NOT_VISITED_INST, instNr++, connectedNode, edge, false, false)); // check if correct *** // Check if node has already been traversed or already is marked if (!connectedNode.Visited) { // Line 8: Enqueue node queue.Enqueue(connectedNode); connectedNode.Visited = true; ListVisualInstruction addConnectedNode = new ListVisualInstruction(UtilGraph.ADD_NODE, instNr, connectedNode); instructions.Add(instNr, new TraverseInstruction(UtilGraph.ENQUEUE_NODE_INST, instNr++, connectedNode, edge, true, false, addConnectedNode)); // Set prev edge connectedNode.PrevEdge = edge; } instructions.Add(instNr, new TraverseInstruction(UtilGraph.END_IF_INST, instNr++, connectedNode, edge, false, false)); } // Line 5: Update for-loop instructions.Add(instNr, new InstructionLoop(UtilGraph.FOR_ALL_NEIGHBORS_INST, instNr++, UtilGraph.NEIGHBORS_VISITED)); // Line 9: End for-loop instructions.Add(instNr, new TraverseInstruction(UtilGraph.END_FOR_LOOP_INST, instNr++, currentNode, false, false)); // <-- instructions.Add(instNr++, new ListVisualInstruction(UtilGraph.DESTROY_CURRENT_NODE, instNr, currentNode)); } // Line 3: condition instructions.Add(instNr, new InstructionLoop(UtilGraph.WHILE_LIST_NOT_EMPTY_INST, instNr++, 0)); // Line 10: end while-loop instructions.Add(instNr, new InstructionBase(UtilGraph.END_WHILE_INST, instNr++)); instructions.Add(instNr, new InstructionBase(Util.FINAL_INSTRUCTION, instNr++)); return(instructions); }
public Dictionary <int, InstructionBase> ShortestPathUserTestInstructions(Node startNode, Node endNode) { Dictionary <int, InstructionBase> instructions = new Dictionary <int, InstructionBase>(); int instNr = 0; // Line 0: (update startnode) instructions.Add(instNr, new InstructionBase(Util.FIRST_INSTRUCTION, instNr++)); // Line 1: Set all vertices of G to inifity graphMain.GraphManager.SetAllNodesDist(UtilGraph.INF); instructions.Add(instNr, new InstructionBase(UtilGraph.SET_ALL_NODES_TO_INFINITY, instNr++)); // Line 2: Create (priority) list List <Node> list = new List <Node>(); instructions.Add(instNr, new InstructionBase(UtilGraph.EMPTY_LIST_CONTAINER, instNr++)); // Line 3: Add starting node and set its cost to 0 list.Add(startNode); startNode.Visited = true; startNode.Dist = 0; ListVisualInstruction addStartNode = new ListVisualInstruction(UtilGraph.PRIORITY_ADD_NODE, instNr, startNode, 0); instructions.Add(instNr, new TraverseInstruction(UtilGraph.ADD_NODE, instNr++, startNode, true, false, addStartNode)); // Line 4: Set total cost (Dist) of start node to 0 instructions.Add(instNr, new InstructionBase(UtilGraph.SET_START_NODE_DIST_TO_ZERO, instNr++)); while (list.Count > 0 && !objectiveFound) { // Line 5: Update while-loop instructions.Add(instNr, new InstructionLoop(UtilGraph.WHILE_LIST_NOT_EMPTY_INST, instNr++, list.Count)); // Node currentNode = list[list.Count - 1]; list.RemoveAt(list.Count - 1); // Line 6: Remove element with lowest distance ListVisualInstruction removeCurrentNode = new ListVisualInstruction(UtilGraph.REMOVE_CURRENT_NODE, instNr, currentNode); instructions.Add(instNr, new TraverseInstruction(UtilGraph.PRIORITY_REMOVE_NODE, instNr++, currentNode, false, true, removeCurrentNode)); //instructions.Add(instNr++, new ListVisualInstruction(UtilGraph.REMOVE_CURRENT_NODE, instNr, currentNode)); // Stop search if end node found and we dont want shortest path to all - stop when first visited instead? (not always global optimal) if (!shortestPathOnToAll && currentNode == endNode) { instructions.Add(instNr, new ListVisualInstruction(UtilGraph.END_NODE_FOUND, instNr++, currentNode)); objectiveFound = true; break; } // Check all nodes connected with current node List <Edge> edges = currentNode.Edges; // Line 7: Update for-loop instructions.Add(instNr, new TraverseInstruction(UtilGraph.FOR_ALL_NEIGHBORS_INST, instNr++, currentNode, false, false)); for (int i = 0; i < edges.Count; i++) { // Checking edge Edge currentEdge = edges[i]; // Dont check edge we came from if (currentEdge == currentNode.PrevEdge) { continue; } // Checking node on the other side of the edge (directed edge scenario) Node connectedNode = currentEdge.OtherNodeConnected(currentNode); if (connectedNode == null || connectedNode.Traversed) { continue; } if (!connectedNode.Visited) { connectedNode.Visited = true; } // Cost between nodes int currentDistAndEdgeCost = currentNode.Dist + currentEdge.Cost; // Line 8: Relax connected node instructions.Add(instNr, new TraverseInstruction(UtilGraph.RELAX_NEIGHBOR_NODE, instNr++, connectedNode, currentEdge, true, false)); // Line 9: If statement instructions.Add(instNr, new ShortestPathInstruction(UtilGraph.IF_DIST_PLUS_EDGE_COST_LESS_THAN, instNr++, currentNode, connectedNode, currentEdge)); // Update cost of connected node if (currentDistAndEdgeCost < connectedNode.Dist) { // Line 10: Update total cost (Dist) of connected node (w) connectedNode.Dist = currentDistAndEdgeCost; instructions.Add(instNr, new ShortestPathInstruction(UtilGraph.UPDATE_CONNECTED_NODE_DIST, instNr++, currentNode, connectedNode, currentEdge)); // Line 11: Update prev edge (Prev) of connected node (w) instructions.Add(instNr, new ShortestPathInstruction(UtilGraph.UPDATE_CONNECTED_NODE_PREV_EDGE, instNr++, connectedNode, currentEdge)); connectedNode.PrevEdge = currentEdge; if (!list.Contains(connectedNode)) { list.Add(connectedNode); } // Sort list such that the lowest distance node gets out first list.Sort(); // List visual int index = list.IndexOf(connectedNode); // Line 12: Add to list instructions.Add(instNr, new ListVisualInstruction(UtilGraph.HAS_NODE_REPRESENTATION, instNr++, connectedNode, index, UtilGraph.PRIORITY_ADD_NODE, UtilGraph.UPDATE_LIST_VISUAL_VALUE_AND_POSITION)); //instructions.Add(instNr++, new InstructionBase(UtilGraph.PRIORITY_ADD_NODE, instNr)); } // Line 13: End if instructions.Add(instNr, new InstructionBase(UtilGraph.END_IF_INST, instNr++)); } // Line 7: Update for-loop instructions.Add(instNr, new InstructionLoop(UtilGraph.FOR_ALL_NEIGHBORS_INST, instNr++, UtilGraph.NEIGHBORS_VISITED)); // Line 14: End for-loop instructions.Add(instNr, new InstructionBase(UtilGraph.END_FOR_LOOP_INST, instNr++)); // <--- instructions.Add(instNr++, new ListVisualInstruction(UtilGraph.DESTROY_CURRENT_NODE, instNr, currentNode)); currentNode.Traversed = true; } // Line 5: condition instructions.Add(instNr, new InstructionLoop(UtilGraph.WHILE_LIST_NOT_EMPTY_INST, instNr++, 0)); // Line 15: End while-loop instructions.Add(instNr, new InstructionBase(UtilGraph.END_WHILE_INST, instNr++)); if (objectiveFound) { graphMain.GraphManager.ShortestPatBacktrackingInstructions(instructions, instNr); } else { instructions.Add(instNr, new InstructionBase(UtilGraph.NO_PATH_FOUND, instNr++)); } // Gather instruction for backtracking return(instructions); }
public override IEnumerator ExecuteDemoInstruction(InstructionBase instruction, bool increment) { Node currentNode = null, connectedNode = null; Edge currentEdge = null, prevEdge = null; // Gather information from instruction if (instruction is TraverseInstruction) { TraverseInstruction travInst = (TraverseInstruction)instruction; if (instruction.Instruction == UtilGraph.ADD_NODE || instruction.Instruction == UtilGraph.PRIORITY_REMOVE_NODE || instruction.Instruction == UtilGraph.FOR_ALL_NEIGHBORS_INST) { currentNode = travInst.Node; } else { connectedNode = travInst.Node; } currentEdge = travInst.PrevEdge; // Do list visual instruction if there is one if (travInst.ListVisualInstruction != null) { graphMain.ListVisual.ExecuteInstruction(travInst.ListVisualInstruction, increment); } } else if (instruction is ShortestPathInstruction) { ShortestPathInstruction spInst = (ShortestPathInstruction)instruction; currentNode = spInst.CurrentNode; connectedNode = spInst.ConnectedNode; currentEdge = spInst.CurrentEdge; prevEdge = spInst.PrevEdge; // Do list visual instruction if there is one if (spInst.ListVisualInstruction != null) { graphMain.ListVisual.ExecuteInstruction(spInst.ListVisualInstruction, increment); } } else if (instruction is InstructionLoop) { i = ((InstructionLoop)instruction).I; //j = ((InstructionLoop)instruction).J; //k = ((InstructionLoop)instruction).K; } // Remove highlight from previous instruction pseudoCodeViewer.ChangeColorOfText(prevHighlightedLineOfCode, Util.BLACKBOARD_TEXT_COLOR); // Gather part of code to highlight int lineOfCode = Util.NO_VALUE; useHighlightColor = Util.HIGHLIGHT_STANDARD_COLOR; switch (instruction.Instruction) { case Util.FIRST_INSTRUCTION: lineOfCode = 0; if (increment) { SetNodePseudoCode(graphMain.GraphManager.StartNode, 0); } else { startNodeAlpha = 's'; } break; case UtilGraph.SET_ALL_NODES_TO_INFINITY: lineOfCode = 1; if (increment) { graphMain.GraphManager.SetAllNodesDist(UtilGraph.INF); } else { graphMain.GraphManager.SetAllNodesDist(UtilGraph.INIT_NODE_DIST); } break; case UtilGraph.EMPTY_LIST_CONTAINER: lineOfCode = 2; break; case UtilGraph.ADD_NODE: SetNodePseudoCode(currentNode, 0); // start node lineOfCode = 3; if (increment) { currentNode.Visited = ((TraverseInstruction)instruction).VisitInst; } else { currentNode.Visited = !((TraverseInstruction)instruction).VisitInst; } break; case UtilGraph.SET_START_NODE_DIST_TO_ZERO: lineOfCode = 4; if (increment) { startNode.Dist = 0; } else { startNode.Dist = UtilGraph.INF; } // Update list visual ListVisualInstruction setStartNodeToZero = new ListVisualInstruction(UtilGraph.SET_START_NODE_DIST_TO_ZERO, 0, startNode, 0); graphMain.ListVisual.ExecuteInstruction(setStartNodeToZero, increment); break; case UtilGraph.WHILE_LIST_NOT_EMPTY_INST: lineOfCode = 5; lengthOfList = i.ToString(); useHighlightColor = UseConditionColor(i != 0); break; case UtilGraph.PRIORITY_REMOVE_NODE: lineOfCode = 6; if (increment) { // Hide all edge cost to make it easier to see node distances graphMain.GraphManager.MakeEdgeCostVisible(false); SetNodePseudoCode(currentNode, 1); yield return(demoStepDuration); // Show the next node we'll work from currentNode.CurrentColor = UtilGraph.TRAVERSE_COLOR; currentNode.DisplayEdgeCost(true); // Display edge costs again graphMain.GraphManager.MakeEdgeCostVisible(true); } else { currentNode.CurrentColor = UtilGraph.VISITED_COLOR; currentNode.DisplayEdgeCost(false); } break; case UtilGraph.FOR_ALL_NEIGHBORS_INST: lineOfCode = 7; if (increment) { if (i != UtilGraph.NEIGHBORS_VISITED) { SetNodePseudoCode(currentNode, 1); } useHighlightColor = UseConditionColor(i != UtilGraph.NEIGHBORS_VISITED); } else { if (currentNode == startNode) { node1Alpha = 'w'; } } break; case UtilGraph.RELAX_NEIGHBOR_NODE: SetNodePseudoCode(connectedNode, 2); lineOfCode = 8; if (increment) { connectedNode.Visited = ((TraverseInstruction)instruction).VisitInst; if (currentEdge != null) { currentEdge.CurrentColor = UtilGraph.VISITED_COLOR; } } else { connectedNode.Visited = !((TraverseInstruction)instruction).VisitInst; if (currentEdge != null) { currentEdge.CurrentColor = Util.STANDARD_COLOR; } } break; case UtilGraph.IF_DIST_PLUS_EDGE_COST_LESS_THAN: lineOfCode = 9; if (increment) { SetNodePseudoCode(connectedNode, 2); edgeCost = currentEdge.Cost; ifStatementContent = CreateIfStatementContent(currentNode.Dist, edgeCost, connectedNode.Dist); } else { // TODO } break; case UtilGraph.UPDATE_CONNECTED_NODE_DIST: lineOfCode = 10; if (increment) { connectedNode.Dist = ((ShortestPathInstruction)instruction).ConnectedNodeNewDist; } else { connectedNode.Dist = ((ShortestPathInstruction)instruction).ConnectedNodeOldDist; } break; case UtilGraph.UPDATE_CONNECTED_NODE_PREV_EDGE: lineOfCode = 11; if (increment) { connectedNode.PrevEdge = prevEdge; } else { connectedNode.PrevEdge = ((ShortestPathInstruction)instruction).OldPrevEdge; } break; case UtilGraph.HAS_NODE_REPRESENTATION: // update/add lineOfCode = 12; ListVisualInstruction listVisualInst = (ListVisualInstruction)instruction; graphMain.ListVisual.ExecuteInstruction(listVisualInst, increment); break; case UtilGraph.END_IF_INST: lineOfCode = 13; break; case UtilGraph.END_FOR_LOOP_INST: lineOfCode = 14; if (this.currentNode != null) { this.currentNode.Traversed = increment; } // Destroy current node in list visual graphMain.ListVisual.ExecuteInstruction(new ListVisualInstruction(UtilGraph.DESTROY_CURRENT_NODE, Util.NO_INSTRUCTION_NR, this.currentNode), increment); break; case UtilGraph.END_WHILE_INST: lineOfCode = 15; IsTaskCompleted = increment; break; } prevHighlightedLineOfCode = lineOfCode; // Highlight part of code in pseudocode yield return(HighlightPseudoCode(CollectLine(lineOfCode), useHighlightColor)); graphMain.WaitForSupportToComplete--; }
public Dictionary <int, InstructionBase> TraverseUserTestInstructions(Node startNode) { Dictionary <int, InstructionBase> instructions = new Dictionary <int, InstructionBase>(); int instNr = 0; // Line 0: Update start node instructions.Add(instNr, new TraverseInstruction(Util.FIRST_INSTRUCTION, instNr++, startNode, false, false)); // Line 1: Create an empty list (stack) Stack <Node> stack = new Stack <Node>(); instructions.Add(instNr, new InstructionBase(UtilGraph.EMPTY_LIST_CONTAINER, instNr++)); // Line 2: Push start node stack.Push(startNode); startNode.Visited = true; ListVisualInstruction addStartNode = new ListVisualInstruction(UtilGraph.ADD_NODE, instNr, startNode); instructions.Add(instNr, new TraverseInstruction(UtilGraph.PUSH_INST, instNr++, startNode, true, false, addStartNode)); while (stack.Count > 0) { // Line 3: Update while-loop instructions.Add(instNr, new InstructionLoop(UtilGraph.WHILE_LIST_NOT_EMPTY_INST, instNr++, stack.Count)); // Line 4: Pop node from stack Node currentNode = stack.Pop(); currentNode.Traversed = true; ListVisualInstruction removeCurrentNode = new ListVisualInstruction(UtilGraph.REMOVE_CURRENT_NODE, instNr, currentNode, 0); instructions.Add(instNr, new TraverseInstruction(UtilGraph.POP_INST, instNr++, currentNode, currentNode.PrevEdge, false, true, removeCurrentNode)); // Go through each edge connected to current node // Line 5: Update for-loop instructions.Add(instNr, new TraverseInstruction(UtilGraph.FOR_ALL_NEIGHBORS_INST, instNr++, currentNode, false, false)); for (int i = 0; i < currentNode.Edges.Count; i++) { Edge edge = currentNode.Edges[i]; Node connectedNode = edge.OtherNodeConnected(currentNode); // No need to check the edge we came from if (edge == currentNode.PrevEdge) { continue; } // Optimizing check //if (connectedNode.Visited || connectedNode.Traversed) // continue; // Line 6: If statement (condition) instructions.Add(instNr, new TraverseInstruction(UtilGraph.IF_NOT_VISITED_INST, instNr++, connectedNode, edge, false, false)); if (!connectedNode.Visited) { // Line 7: Push node on top of stack stack.Push(connectedNode); connectedNode.Visited = true; ListVisualInstruction addConnectedNode = new ListVisualInstruction(UtilGraph.ADD_NODE, instNr, connectedNode); instructions.Add(instNr, new TraverseInstruction(UtilGraph.PUSH_INST, instNr++, connectedNode, edge, true, false, addConnectedNode)); // Set prev edge connectedNode.PrevEdge = edge; } // Line 8: End if statement instructions.Add(instNr, new TraverseInstruction(UtilGraph.END_IF_INST, instNr++, connectedNode, edge, false, false)); } // Line 5: Update for-loop instructions.Add(instNr, new InstructionLoop(UtilGraph.FOR_ALL_NEIGHBORS_INST, instNr++, UtilGraph.NEIGHBORS_VISITED)); // Line 9: End for-loop instructions.Add(instNr, new TraverseInstruction(UtilGraph.END_FOR_LOOP_INST, instNr++, currentNode, false, false)); // <-- instructions.Add(instNr++, new ListVisualInstruction(UtilGraph.DESTROY_CURRENT_NODE, instNr, currentNode)); } // Line 3: condition instructions.Add(instNr, new InstructionLoop(UtilGraph.WHILE_LIST_NOT_EMPTY_INST, instNr++, 0)); // Line 10: End while-loop instructions.Add(instNr, new InstructionBase(UtilGraph.END_WHILE_INST, instNr++)); instructions.Add(instNr, new InstructionBase(Util.FINAL_INSTRUCTION, instNr++)); return(instructions); }
// User test public int PrepareNextInstruction(InstructionBase instruction) { string inst = instruction.Instruction; Debug.Log(">>> " + instruction.DebugInfo()); // First check whether the instruction contains a node and/or destination bool gotNode = !graphAlgorithm.SkipDict[Util.SKIP_NO_ELEMENT].Contains(inst); bool noDestination = graphAlgorithm.SkipDict[Util.SKIP_NO_DESTINATION].Contains(inst); // List visual Update if (instruction is ListVisualInstruction) { // Only provide list visual support until <lvl> if (graphSettings.Difficulty > UtilGraph.LIST_VISUAL_MAX_DIFFICULTY) { return(1); } ListVisualInstruction listVisualInst = (ListVisualInstruction)instruction; listVisual.ExecuteInstruction(listVisualInst, true); //Debug.Log("List visual instruction: " + listVisualInst.DebugInfo()); } else { Node node = null; if (gotNode) { if (instruction is TraverseInstruction) { TraverseInstruction traverseInstruction = (TraverseInstruction)instruction; //Debug.Log("Traverse instruction: " + traverseInstruction.DebugInfo()); // Get the Sorting element node = traverseInstruction.Node; // Hands out the next instruction node.Instruction = traverseInstruction; // Set goal posManager.CurrentGoal = node; // Reset if pointer must be used on the same node twice if (traverseInstruction.VisitInst && pointer.prevNodeShot == node) { pointer.prevNodeShot = null; } // Reset position manager if the user already stands on top of the node if (traverseInstruction.TraverseInst && posManager.ReportedNode == node) { posManager.ReportedNode = null; } // Give this sorting element permission to give feedback to progress to next intstruction node.NextMove = NextIsUserMove(inst); // Traverse instruction extra switch (inst) { // Highlight the node we are currently going to work at case UtilGraph.DEQUEUE_NODE_INST: case UtilGraph.POP_INST: case UtilGraph.PRIORITY_REMOVE_NODE: // Hide all edge cost to make it easier to see node distances if (graphSettings.GraphTask == UtilGraph.SHORTEST_PATH) { graphManager.MakeEdgeCostVisible(false); } break; case UtilGraph.FOR_ALL_NEIGHBORS_INST: // Make edge cost visible again if (graphSettings.GraphTask == UtilGraph.SHORTEST_PATH) { graphManager.MakeEdgeCostVisible(true); } break; } // Perform list visual instruction in next step (when current instruction has been correctly performed) if (traverseInstruction.ListVisualInstruction != null) { updateListVisualInstruction = traverseInstruction.ListVisualInstruction; } } else if (instruction is ShortestPathInstruction) { ShortestPathInstruction spInst = (ShortestPathInstruction)instruction; //Debug.Log("Shortest path instruction: " + spInst.DebugInfo()); // Get the Sorting element if (spInst.CurrentNode != null) { node = spInst.CurrentNode; } else { node = spInst.ConnectedNode; } // Hands out the next instruction node.Instruction = spInst; // Set goal posManager.CurrentGoal = node; // Give this sorting element permission to give feedback to progress to next intstruction node.NextMove = NextIsUserMove(inst); // Shortest path extra switch (inst) { case UtilGraph.IF_DIST_PLUS_EDGE_COST_LESS_THAN: // Turn off highlight effect of previous line pseudoCodeViewer.ChangeColorOfText(8, Util.BLACKBOARD_TEXT_COLOR); // Since we highlighted the color and/or text position of the node/edge we are working on (highlighting purpose) in the previous instruction, now we reset them // Changed color of node spInst.ConnectedNode.CurrentColor = UtilGraph.VISITED_COLOR; // Reset text color/position of the edge cost spInst.CurrentEdge.CurrentColor = UtilGraph.VISITED_COLOR; // Perform sub task: calculate dist (current node) + edge cost to the connected node if (!autoCalculation) { usingCalculator = true; pointer.AllowShooting = false; calculator.InitCalculation(Calculator.GRAPH_TASK); calculator.SpawnDeviceInfrontOfPlayer(); } break; } // Perform list visual instruction in next step (when current instruction has been correctly performed) if (spInst.ListVisualInstruction != null) { updateListVisualInstruction = spInst.ListVisualInstruction; } } } } // Display help on blackboard if (graphSettings.Difficulty <= Util.PSEUDO_CODE_HIGHTLIGHT_MAX_DIFFICULTY) { WaitForSupportToComplete++; StartCoroutine(graphAlgorithm.UserTestHighlightPseudoCode(instruction, gotNode));// && !noDestination)); } // InstructionBase extra switch (inst) { case UtilGraph.SET_ALL_NODES_TO_INFINITY: graphManager.SetAllNodesDist(UtilGraph.INF); break; case UtilGraph.SET_START_NODE_DIST_TO_ZERO: // Find start node and set distance to 0 Node startNode = graphManager.StartNode; startNode.Dist = 0; // If list visual: update value if (Settings.Difficulty <= UtilGraph.LIST_VISUAL_MAX_DIFFICULTY) { listVisual.FindNodeRepresentation(startNode).UpdateSurfaceText(UtilGraph.DIST_UPDATE_COLOR); } break; case UtilGraph.MARK_END_NODE: Node endNode = graphManager.EndNode; endNode.CurrentColor = UtilGraph.SHORTEST_PATH_COLOR; endNode.PrevEdge.CurrentColor = UtilGraph.SHORTEST_PATH_COLOR; break; case UtilGraph.END_FOR_LOOP_INST: if (graphSettings.Difficulty <= UtilGraph.LIST_VISUAL_MAX_DIFFICULTY) { listVisual.DestroyCurrentNode(); } break; case UtilGraph.NO_PATH_FOUND: case Util.FINAL_INSTRUCTION: // No path found WaitForSupportToComplete++; StartCoroutine(FinishUserTest()); break; } //Debug.Log("Got node: " + gotNode + ", no destination: " + noDestination); if (gotNode && !noDestination) { return(0); } //Debug.Log("Nothing to do for player, get another instruction"); return(1); }
protected override void UserTestUpdate() { // If a node is set to be visited or traversed, wait until it has been achieved if (userTestGoalActive && !posManager.PlayerWithinGoalPosition) { return; } else { userTestGoalActive = false; } // First check if user test setup is complete if (userTestManager.HasInstructions()) { // If a calculation is required to progress in the algorithm if (algorithmName == Util.DIJKSTRA && usingCalculator) { // Check if it's in process and whether the equal button has been clicked if (calculator.CalculationInProcess && calculator.EqualButtonClicked) { InstructionBase inst = userTestManager.GetInstruction(); ShortestPathInstruction spInst = null; if (inst != null && inst.Instruction == UtilGraph.IF_DIST_PLUS_EDGE_COST_LESS_THAN) { spInst = ((ShortestPathInstruction)userTestManager.GetInstruction()); } else { return; } // When equal buttons has been clicked, check whether the input data is correct int node1Dist = spInst.CurrentNode.Dist; int edgeCost = spInst.CurrentEdge.Cost; int node2Dist = spInst.ConnectedNode.Dist; bool correctUserInput = calculator.ControlUserInput(node1Dist, edgeCost, node2Dist); // If input data was correct, then progress to next instruction (add only one) if (correctUserInput && userTestManager.ReadyForNext != userTestManager.UserActionToProceed) { userTestManager.IncrementTotalCorrect(); userTestManager.ReadyForNext += 1; ((Dijkstra)graphAlgorithm).IfStatementContent = calculator.IfStatementContent(); pseudoCodeViewer.SetCodeLine(((Dijkstra)graphAlgorithm).CollectLine(9), Util.BLACKBOARD_TEXT_COLOR); calculator.FeedbackReceived = true; } else if (!calculator.FeedbackReceived) { userTestManager.Mistake(); calculator.FeedbackReceived = true; } } else if (!calculator.CalculationInProcess) { // Feedback is given on the calculator, so when calculationInProcess = false (calculation completed), we continue usingCalculator = false; pointer.AllowShooting = true; } } // Continue when user has finished sub task, or else whenever ready if (userTestManager.ReadyForNext == userTestManager.UserActionToProceed) { if (graphSettings.Difficulty <= UtilGraph.LIST_VISUAL_MAX_DIFFICULTY && updateListVisualInstruction != null) { listVisual.ExecuteInstruction(updateListVisualInstruction, true); updateListVisualInstruction = null; } // Reset counter userTestManager.ReadyForNext = 0; // Check if we still have any instructions if (!userTestManager.HasInstructions()) // ??? { graphAlgorithm.IsTaskCompleted = true; } else { // Still got instructions? bool hasInstruction = userTestManager.IncrementToNextInstruction(); // Hot fix - solve in some other way? if (hasInstruction) { userTestManager.ReadyForNext += PrepareNextInstruction(userTestManager.GetInstruction()); } } } if (Settings.UserTestScore) { blackboard.ChangeText(1, userTestManager.FillInBlackboard()); } } }