<taskModel about="urn:cetask.wpi.edu:examples:Inquiry" xmlns="http://ce.org/cea-2018">

 <!-- 
      Mike Sao Pedro
      mikesp@wpi.edu
      
      Main task: perform all parts of the scientific method.
      
      Here, I envision perhaps noticing what window the user clicks
      (hypoth spec, experiment spec, conclusion spec) in order to do
      the decomposition. 
  -->
  <task id="PerformExperiment">
  	<input name="experiment" type="Experiment"/>
    <output name="hypothesis" type="Hypothesis"/>
    
  	<!-- 
  	   Have student perform all parts of the scientific method. 
  	   Here the student will be asked to fill in specific tests.
  	-->
  	<subtasks id="allScientificMethod">
  	
  	   <step name="formHypothesis" task="FormHypothesis"/>
  	   <step name="runExperiments" task="RunExperiments"/>
  	   <!--  
  	   <step name="formConclusions" task="FormConclusions"/>
  	   -->
  	   
  	   <!-- The experiments are geared towards the hypothesis selected -->
  	   <binding slot="$formHypothesis.simulation" value="$this.experiment.simulation"/>
  	   <binding slot="$this.hypothesis" value="$formHypothesis.hypothesis"/>
  	   <binding slot="$runExperiments.hypothesis" value="$this.hypothesis"/>
  	            
  	   <!-- 
  	   <binding slot="$formConclusions.table" 
  	            value="$runExperiments.table"/>
  	   <binding slot="$formConclusions.hypothesis"
  	            value="$formHypothesis.hypothesis"/>
  	     -->
  	</subtasks>
  </task>


<!-- ********************************************************************** -->
<!-- ********************************************************************** -->

  
  <!-- 
      Given a simulation specification, make a student fill in
      a hypothesis. Forming a hypothesis consists of seeing how
      and independent variable affects an outcome variable.
      
      requires="independentVar comparator outcomeVar"
   -->
  <task id="FormHypothesis">
  	<input name="simulation" type="Simulation"/>
  	<output name="independentVarValue" type="string"/>
  	<output name="comparatorValue" type="string"/>
  	<output name="outcomeVarValue" type="string"/>
  	<output name="hypothesis" type="Hypothesis"/>

  	<subtasks id="fillHypothesisTemplate">
  	   <step name="independentVar" task="SelectIndependentVar" />
  	   <step name="comparator" task="SelectComparator" />
  	   <step name="outcomeVar" task="SelectOutcomeVar" />
  	   <step name="buildHypothesis" task="BuildHypothesis"/>
  	   
  	   <!-- input bindings: indep/dep vars come from simulation def. -->
  	   <binding slot="$this.comparatorValue" value="$comparator.selection"/>
  	   <binding slot="$this.independentVarValue" value="$independentVar.selection"/>
  	   <binding slot="$this.outcomeVarValue" value="$outcomeVar.selection"/>
  	   <binding slot="$buildHypothesis.comparator" value="$comparator.selection"/>
  	   <binding slot="$buildHypothesis.target" value="$independentVar.selection"/>
  	   <binding slot="$buildHypothesis.outcome" value="$outcomeVar.selection"/>
  	   <binding slot="$this.hypothesis" value="$buildHypothesis.hypothesis"/>
  	   
  	</subtasks>
  	
  </task>
  
  <!-- Choose the target IndependentVariable from the list. Can be done by user or sw agent. -->
  <task id="SelectIndependentVar">
  	<output name="selection" type="string"/>
  	
  	<postcondition>
  	  $this.selection != null;
  	  if($this.selection != null) { $this.selection != undefined; }
  	  contains(independentVariableNames, $this.selection);
  	</postcondition>
  	
  	<!-- 
  	   If user can't do the step for whatever reason, this script will do it.
  	   This enables the task to be done by the pedagogical agent instead of the user
  	   (maybe if it's in a demonstration mode) 
  	 -->
  	<script>
  	  $this.selection = random_selection(independentVariableNames);
  	</script>
  </task>
  
  <!-- Choose an OutcomeVariable from the list. Can be done by user or sw agent. -->
  <task id="SelectOutcomeVar">
  	<output name="selection" type="string"/>
  	
  	<postcondition>
  	  $this.selection != undefined;
  	  contains(outcomeVariableNames, $this.selection);
  	</postcondition>
  	
  	<script>
  	  $this.selection = random_selection(outcomeVariableNames);
  	</script>	
  </task>
  
  <!-- Choose a comparator from the list. Can be done by user or sw agent. -->
  <task id="SelectComparator">
  	<output name="selection" type="string"/>
  	
  	<postcondition>
  	  $this.selection != undefined;
  	  contains(comparators, $this.selection);
  	</postcondition>
  	
  	<script>
  	  $this.selection = random_selection(comparators);
  	</script>
  	
  </task>
  
  <!-- 
      Have the sw agent construct the Hypothesis object.
      Call 'execute'. 
    -->
  <task id="BuildHypothesis">
     <input name="target" type="string"/>
     <input name="comparator" type="string"/>
     <input name="outcome" type="string"/>
     <output name="hypothesis" type="Hypothesis"/>
     
     <precondition>
        $this.target != undefined;
        $this.comparator != undefined;
        $this.outcome != undefined;
     </precondition>
     
     <postcondition>
        $this.hypothesis != undefined;
        $this.hypothesis != null;
     </postcondition>
     
     <script>
         print("...I am constructing the Hypothesis object...");
         $this.hypothesis = new Hypothesis($this.target, $this.outcome, $this.comparatorValue);
     </script>
  </task>
  
  
<!-- ********************************************************************** -->
<!-- ********************************************************************** -->
  
  <!-- 
     The "meat": how will a student set up their experiments?
     For now, I am assuming they will run TWO experiments to do CVS 
     (just like Klahr's paper).
     
     Setup2 is the more important since it must be compared to Setup1
     
   -->
  <task id="RunExperiments">
    <input name="hypothesis" type="Hypothesis"/>
    <output name="trial1" type="Trial"/>
    <output name="trial2" type="Trial"/>
    
    <!-- May need tail recursion on SetupTrialCheckCVS instead? -->
    <subtasks id="fillInTrials">
       <step name="setup1" task="SetupTrial"/>
       <step name="outcome1" task="RecordOutcome"/>
       <step name="buildtrial1" task="BuildTrial"/>
       <step name="incrementtrial1" task="IncrementTrial"/>
       <step name="setup2" task="SetupTrialCheckCVS" minOccurs="1" maxOccurs="unbounded"/>
       <step name="outcome2" task="RecordOutcome"/>
       <step name="buildtrial2" task="BuildTrial"/>
       <step name="incrementtrial2" task="IncrementTrial"/>

	   <!-- Binding to ensure CVS works -->
       <binding slot="$setup2.hypothesis" value="$this.hypothesis"/>
       <binding slot="$setup2.checkVars" value="$buildtrial1.indepvars"/>

       <!-- outcome bindings -->
       <binding slot="$outcome1.leftRampAngle" value="$setup1.leftRampAngle"/>
       <binding slot="$outcome1.ballStartPosition" value="$setup1.ballStartPosition"/>
       <binding slot="$outcome1.leftRampFriction" value="$setup1.leftRampFriction"/>
       <binding slot="$outcome1.ballType" value="$setup1.ballType"/>
       <binding slot="$outcome2.leftRampAngle" value="$setup2.leftRampAngle"/>
       <binding slot="$outcome2.ballStartPosition" value="$setup2.ballStartPosition"/>
       <binding slot="$outcome2.leftRampFriction" value="$setup2.leftRampFriction"/>
       <binding slot="$outcome2.ballType" value="$setup2.ballType"/>
       
       <!-- Trial object binding -->
       <binding slot="$buildtrial1.leftRampAngle" value="$setup1.leftRampAngle"/>
       <binding slot="$buildtrial1.ballStartPosition" value="$setup1.ballStartPosition"/>
       <binding slot="$buildtrial1.leftRampFriction" value="$setup1.leftRampFriction"/>
       <binding slot="$buildtrial1.ballType" value="$setup1.ballType"/>
       <binding slot="$buildtrial1.distance" value="$outcome1.distance"/>
       <binding slot="$buildtrial1.time" value="$outcome1.time"/>
       <binding slot="$buildtrial2.leftRampAngle" value="$setup2.leftRampAngle"/>
       <binding slot="$buildtrial2.ballStartPosition" value="$setup2.ballStartPosition"/>
       <binding slot="$buildtrial2.leftRampFriction" value="$setup2.leftRampFriction"/>
       <binding slot="$buildtrial2.ballType" value="$setup2.ballType"/>
       <binding slot="$buildtrial2.distance" value="$outcome2.distance"/>
       <binding slot="$buildtrial2.time" value="$outcome2.time"/>
       
	   <!-- Final binding to trials -->
       <binding slot="$this.trial1" value="$buildtrial1.trial"/>
       <binding slot="$this.trial2" value="$buildtrial2.trial"/>
    </subtasks>    
  </task>
  
  <!-- 
     Each of these will be set by the GUI elements
     For convenience, aggregate all the variables at the end for other tasks to use 
   -->
  <task id="SetupTrial">
    <output name="leftRampAngle" type="string"/>
    <output name="ballStartPosition" type="string"/>
    <output name="leftRampFriction" type="string"/>
    <output name="ballType" type="string"/>
    
    <postcondition>
       $this.leftRampAngle != undefined;
       $this.ballStartPosition != undefined;
       $this.leftRampFriction != undefined;
       $this.ballType != undefined;
    </postcondition>
  </task>
  
  <!-- 
     Record the results of running an experiment. The system always does this.
     For convenience, aggregate all the variables at the end for other tasks to use
     
     This task is capable of automatically recording the data to the graphical table.       
   -->
  <task id="RecordOutcome">
    <input name="leftRampAngle" type="string"/>
    <input name="ballStartPosition" type="string"/>
    <input name="leftRampFriction" type="string"/>
    <input name="ballType" type="string"/>
  	<output name="distance" type="number"/>
  	<output name="time" type="number"/>
  	
  	<precondition>
  	   $this.leftRampAngle != undefined;
  	   $this.ballStartPosition != undefined;
  	   $this.leftRampFriction != undefined;
  	   $this.ballType != undefined;
  	</precondition>
  	
  	<postcondition>
  	   $this.distance != undefined;
  	   $this.time != undefined;
  	</postcondition>
  	
  	<script>
  	   // --- Get the distance and time from the GUI
  	   importClass(Packages.edu.assistment.experiments.pedagogy.PedagogicalAgent);
  	   
  	   // --- Nasty; wait for the simulation thread to stop (yielding results)
  	   while(!PedagogicalAgent.simController.resultsAvailable());
  	   
  	   // --- Get the results
  	   $this.distance = PedagogicalAgent.simModel.getDistanceRolledFromIncline();
  	   $this.time = PedagogicalAgent.simModel.getCurrentTime();
  	   
  	   // --- Put them in the table 
  	   PedagogicalAgent.trialTable.getModel().setValueAt($this.leftRampAngle, trial-1, 1);
  	   PedagogicalAgent.trialTable.getModel().setValueAt($this.leftRampFriction, trial-1, 2);
  	   PedagogicalAgent.trialTable.getModel().setValueAt($this.ballType, trial-1, 3);
  	   PedagogicalAgent.trialTable.getModel().setValueAt($this.ballStartPosition, trial-1, 4);  	   
  	   PedagogicalAgent.trialTable.getModel().setValueAt($this.distance, trial-1, 5);
  	   PedagogicalAgent.trialTable.getModel().setValueAt($this.time, trial-1, 6);
  	</script>	

  </task>
  
  
  <!-- Have sw agent keep track of current trial # -->
  <task id="IncrementTrial">
  	<script>
        trial++;  	     	   
  	</script>
  </task>
  
  
  <!-- Have sw build the trial object -->
  <task id="BuildTrial">
    <input name="leftRampAngle" type="string"/>
    <input name="ballStartPosition" type="string"/>
    <input name="leftRampFriction" type="string"/>
    <input name="ballType" type="string"/>
  	<input name="distance" type="number"/>
  	<input name="time" type="number"/>
  	<output name="trial" type="Trial"/>
  	<output name="indepvars" type="VariableCollection"/>
  	<output name="outcomevars" type="VariableCollection"/>
  	
  	<script>
  	     // --- Indep vars
         var leftRampAngleVar = new IndependentVariable("steepness", $this.leftRampAngle);
         var ballStartPositionVar = new IndependentVariable("run length", $this.ballStartPosition);
         var leftRampFrictionVar = new IndependentVariable("surface type", $this.leftRampFriction);
         var ballTypeVar = new IndependentVariable("ball type", $this.ballTypeValue);
         $this.indepvars = new VariableCollection([leftRampAngleVar, ballStartPositionVar, leftRampFrictionVar, ballTypeVar]);

         // --- Outcome vars
  		 var distanceVar = new OutcomeVariable("distance", $this.distance);
  		 var timeVar = new OutcomeVariable("time", $this.time);
         $this.outcomevars = new VariableCollection([distanceVar, timeVar]);
         
         $this.trial = new Trial($this.indepvars, $this.outcomevars);
  	</script>
     
  </task>
  
  <!-- If CVS strategy satisfied, this task will not be needed -->
  <task id="SetupTrialCheckCVS">
     <input name="hypothesis" type="Hypothesis"/>
     <input name="checkVars" type="VariableCollection"/>
     <output name="leftRampAngle" type="string"/>
     <output name="ballStartPosition" type="string"/>
     <output name="leftRampFriction" type="string"/>
     <output name="ballType" type="string"/>
     
     <subtasks id="performAndCheck">
     	<step name="setup" task="SetupTrial"/>
     	<step name="buildVarCollection" task="BuildVariableCollection"/>
     	<step name="check" task="CheckCVS"/>
     	
     	<binding slot="$this.leftRampAngle" value="$setup.leftRampAngle"/>
     	<binding slot="$this.ballStartPosition" value="$setup.ballStartPosition"/>
     	<binding slot="$this.leftRampFriction" value="$setup.leftRampFriction"/>
     	<binding slot="$this.ballType" value="$setup.ballType"/>
     	<binding slot="$buildVarCollection.leftRampAngle" value="$setup.leftRampAngle"/>
     	<binding slot="$buildVarCollection.ballStartPosition" value="$setup.ballStartPosition"/>
     	<binding slot="$buildVarCollection.leftRampFriction" value="$setup.leftRampFriction"/>
     	<binding slot="$buildVarCollection.ballType" value="$setup.ballType"/>
     	
     	<binding slot="$check.hypothesis" value="$this.hypothesis"/>
     	<binding slot="$check.checkVars" value="$this.checkVars"/>
     	<binding slot="$check.setupVars" value="$buildVarCollection.variables"/>
     </subtasks>
  </task>

  <!-- Construct the variable collection used in CVS comparison -->
  <task id="BuildVariableCollection">
     <input name="leftRampAngle" type="string"/>
     <input name="ballStartPosition" type="string"/>
     <input name="leftRampFriction" type="string"/>
     <input name="ballType" type="string"/>
     <output name="variables" type="VariableCollection"/>
  
     <script>
         var leftRampAngleVar = new IndependentVariable("steepness", $this.leftRampAngle);
         var ballStartPositionVar = new IndependentVariable("run length", $this.ballStartPosition);
         var leftRampFrictionVar = new IndependentVariable("surface type", $this.leftRampFriction);
         var ballTypeVar = new IndependentVariable("ball type", $this.ballTypeValue);
         $this.variables = new VariableCollection([leftRampAngleVar, ballStartPositionVar, leftRampFrictionVar, ballTypeVar]);     
     </script>
  </task>
    
  <!-- 
      Determine if the two experiments the user has set up is correct. 
      Engage in scaffolding if not corrected.
   -->
  <task id="CheckCVS">
  	<input name="hypothesis" type="Hypothesis"/>
  	<input name="checkVars" type="VariableCollection"/>
  	<input name="setupVars" type="VariableCollection"/>

    <!-- The hypothesis value was not changed between the two trials -->  	
  	<subtasks id="hypothesisValueUnchanged">
  	    <step name="repair" task="RepairUnchangedHypothesisValue"/>
  	    
  		<applicable>
  		    print("hyp unchanged");
  		    print($this.checkVars);
  		    print($this.setupVars);
  			findVariable($this.hypothesis.independentVariable, $this.checkVars.vars).value ==
  			findVariable($this.hypothesis.independentVariable, $this.setupVars.vars).value;
  		</applicable>
  		
  		<binding slot="$repair.var1" value="findVariable($this.hypothesis.independentVariable.name, $this.setupVars.vars)"/>
  		<binding slot="$repair.var2" value="findVariable($this.hypothesis.independentVariable.name, $this.checkVars.vars)"/>
  	</subtasks>

    <!-- The other variables not mentioned in the hypothesis were changed -->  	  	
  	<subtasks id="variablesNotControlled">
  	    <step name="repair" task="RepairVariablesNotControlled"/>

  		<applicable>
  		    print("not controlled");
  		    changedVariables($this.hypothesis.independentVariable, $this.checkVars.vars, $this.setupVars.vars);
  		</applicable>
  	</subtasks>
  	
  </task>
    
  <!-- Make sure the variables have different values -->  
  <task id="RepairUnchangedHypothesisValue">
     <input name="var1" type="IndependentVariable"/>
     <input name="var2" type="IndependentVariable"/>
     
     <postcondition sufficient="true">
       $this.var1.value != $this.var2.value; 
     </postcondition>
  </task>
      
  <task id="RepairVariablesNotControlled">
     <input name="repairError" type="number"/>
  </task>
  
  
<!-- ********************************************************************** -->
<!-- ********************************************************************** -->    
    
  <task id="FormConclusions">
    <input name="hypothesis" type="Hypothesis"/>
    <input name="trial1" type="Trial"/>
    <input name="trial2" type="Trial"/>
  </task>


<!-- ********************************************************************** -->
<!-- ********************************************************************** -->    
<!-- ********************************************************************** -->
<!-- ********************************************************************** -->    
<!-- ********************************************************************** -->
<!-- ********************************************************************** -->    
<!-- ********************************************************************** -->
<!-- ********************************************************************** -->    
  
  <!-- Define all the elements associated with the system -->
  <script init="true">
  
    function IndependentVariable (name, value) 
    {
      this.name = name;
      this.value = value;
    }
    
    function OutcomeVariable (name, value) 
    {
      this.name = name;
      this.value = value;
    }
    
    function Simulation (indepVarsNames, outcomeVarsNames)
    {
      this.independentVariableNames = indepVarsNames;
      this.outcomeVariablesNames = outcomeVarsNames;
    }
    
    function Hypothesis (indepVar, outcomeVar, comp)
    {
      this.comparator = comp;
      this.independentVariable = indepVar;
      this.outcomeVariable = outcomeVar;
    }
    
    function Experiment (sim)
    {
      this.simulation = sim;
    }
    
    function Trial (inputVars, outputVars)
    {
      this.inputVariables = inputVars;
      this.outputVariables = outputVars;
    }
    
    function TrialSet(trials)
    {
      this.trials = trials;
    }
    
    function VariableCollection(vs)
    {
      this.vars = vs;
    }
        
    // +list: list of elements,
    // +elt: element potentially in list
    //
    // return: true if elt in list, false otherwise.
    function contains (list, elt) 
    {
       //print(list)
       //print(elt)
       if(elt == undefined) return false;
       
       return list.indexOf(elt) != -1;
    }

    // return: random element in the list
    function random_selection(list)
    {
       return list[(Math.floor( Math.random() * (list.length)) % list.length)];
    }
    
    // Return a variable in the list with matching name
    // Return: IndependentVariable
    function findVariable(name, varlist)
    {
       print('name: ' + name);
       for(i=0; i &lt; varlist.length; i++)
       {
          print('varlist ' + i + '  name: ' + varlist[i].name);
          if(varlist[i].name == name)
          {
             print('match!');
             return varlist[i];
          }
       }
       print('ERROR! NO MATCH in findVariable for: ' + name);
    }
    
    // Check if any values other than the one w/ name given as input have the same values
    // Return: true if a variable is changed, false otherwise
    function changedVariables(name, vars1, vars2)
    {
       print('changedVariables');
       print('name: ' + name);
       print(vars1);
       print(vars2);
       for(i=0; i &lt; vars1.length; i++)
       {
          // Don't use the hypothesis variable since we DO want that to differ!
          if(vars1[i].name != name)
          {
             matchVar = findVariable(vars1[i].name, vars2);
             print(matchVar.value + " =?= " + vars1[i].value);
             if(matchVar.value != vars1[i].value)
             {
                print("Changed var! Returning true.");
                return true;
             }
          } 
       }
       
       print("CVS done correctly -- returning false");
       return false;
    }
    
    // --- WORLD OBJECTS ---
    var independentVariableNames = ["steepness", "run length", "ball type", "surface type"];
    var outcomeVariableNames = ["distance", "time"];
    var comparators = ["increase", "decrease", "stay the same"];    
        
    var sim = new Simulation(independentVariableNames, outcomeVariableNames);
    var exp = new Experiment(sim);
    
    // --- Global counter for trial number
    var trial = 1;
    
    // --- TEST DATA FOR /test FILES ---
    var hyp = new Hypothesis("steepness", "distance", "increase");
    
    // var leftRampAngle = new IndependentVariable("steepness", "");
    // var ballStartPosition = new IndependentVariable("run length", "");
    // var leftRampSurfaceType = new IndependentVariable("surface type", "");
    // var ballType = new IndependentVariable("ball type", "");
    // var distance = new OutcomeVariable("distance", "");
    // var time = new OutcomeVariable("time", "");
    //
    // var indepVars = 
    //   new VariableCollection([leftRampAngle, ballStartPosition, 
    //                           leftRampSurfaceType, ballType]);
    // var outcomeVars = new VariableCollection([distance, time]);
    
  </script>

</taskModel>