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--; }
// 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); }
// Update the node status based on the instruction protected void UpdateNodeState() { if (nodeInstruction != null) { // Debugging instruction = nodeInstruction.Instruction; status = nodeInstruction.Status; // This node is the next to be visited (shot at) if (nodeInstruction is TraverseInstruction) { TraverseInstruction travInst = (TraverseInstruction)nodeInstruction; // If visit (shoot at node) if (travInst.VisitInst) { visitNextMove = true; if (graphMain.Settings.Difficulty <= UtilGraph.ANIMATION_DIRECTION_MAX_DIFFICULTY) { animator.SetBool("NodeCheck", true); } } // This node is the next to be traversed (player move to node) if (travInst.TraverseInst) { traverseNextMove = true; if (graphMain.Settings.Difficulty <= UtilGraph.ANIMATION_DIRECTION_MAX_DIFFICULTY) { animator.SetBool("NodeTraverse", true); } } // Set the edge between the node we traversed from to reach this node if (travInst.PrevEdge != null) { switch (algorithm) { case Util.BFS: case Util.DFS: case Util.DFS_RECURSIVE: prevEdge = travInst.PrevEdge; break; case Util.DIJKSTRA: currentEdge = travInst.PrevEdge; break; } } } else if (nodeInstruction is ShortestPathInstruction) { ShortestPathInstruction spInst = (ShortestPathInstruction)nodeInstruction; switch (spInst.Instruction) { case UtilGraph.UPDATE_CONNECTED_NODE_DIST: if (spInst.CurrentNode == this) { spInst.ConnectedNode.Dist = spInst.ConnectedNodeNewDist; } else if (spInst.ConnectedNode == this) { Dist = spInst.ConnectedNodeNewDist; } break; case UtilGraph.UPDATE_CONNECTED_NODE_PREV_EDGE: if (spInst.CurrentNode == this) { spInst.ConnectedNode.PrevEdge = spInst.PrevEdge; } else if (spInst.ConnectedNode == this) { prevEdge = spInst.PrevEdge; } break; } } } }
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()); } } }