Example #1
0
 protected function adjust_fraction($fraction, question_attempt_pending_step $pendingstep)
 {
     $totaltries = $this->qa->get_step(0)->get_behaviour_var('_triesleft');
     $responses = array();
     $lastsave = array();
     foreach ($this->qa->get_step_iterator() as $step) {
         if ($step->has_behaviour_var('submit') && $step->get_state() != question_state::$invalid) {
             $responses[] = $step->get_qt_data();
             $lastsave = array();
         } else {
             $lastsave = $step->get_qt_data();
         }
     }
     $lastresponse = $pendingstep->get_qt_data();
     if (!empty($lastresponse)) {
         $responses[] = $lastresponse;
     } else {
         if (!empty($lastsave)) {
             $responses[] = $lastsave;
         }
     }
     return $this->question->compute_final_grade($responses, $totaltries);
 }
 protected function process_parts_that_can_be_graded(question_attempt_pending_step $pendingstep, $finalsubmit)
 {
     // Get the response we are processing.
     if ($finalsubmit) {
         $laststep = $this->qa->get_last_step();
         $response = $laststep->get_qt_data();
     } else {
         $response = $pendingstep->get_qt_data();
     }
     // Get last graded response for each part.
     $lastgradedresponses = array();
     $currenttries = array();
     $currentpenalties = array();
     $currentfractions = array();
     $currentrawfractions = array();
     $prevseenresponse = array();
     $steps = $this->qa->get_reverse_step_iterator();
     if ($finalsubmit) {
         $steps->next();
     }
     foreach ($steps as $step) {
         foreach ($step->get_behaviour_data() as $name => $value) {
             if (!preg_match('~_tries_(.*)$~', $name, $matches)) {
                 continue;
             }
             $oldresponse = $step->get_qt_data();
             $partname = $matches[1];
             if (array_key_exists($partname, $currenttries)) {
                 // We already have a most recent try for this part, but now
                 // have an older response that was a try for this part, and
                 // we want to know if the current response is the same as this.
                 if ($this->question->is_same_response_for_part($partname, $oldresponse, $response)) {
                     $prevseenresponse[$partname] = true;
                 }
                 continue;
             }
             $lastgradedresponses[$partname] = $oldresponse;
             $currenttries[$partname] = $value;
             $currentpenalties[$partname] = $step->get_behaviour_var('_penalty_' . $partname);
             $currentfractions[$partname] = $step->get_behaviour_var('_fraction_' . $partname);
             $currentrawfractions[$partname] = $step->get_behaviour_var('_rawfraction_' . $partname);
         }
     }
     $partscores = $this->question->grade_parts_that_can_be_graded($response, $lastgradedresponses, $finalsubmit);
     foreach ($partscores as $partname => $partscore) {
         if ($partscore->errors) {
             $pendingstep->set_behaviour_var('_errors_' . $partname, 1);
             continue;
         }
         if (!array_key_exists($partname, $currentpenalties)) {
             $currenttries[$partname] = 0;
             $currentpenalties[$partname] = 0;
             $currentfractions[$partname] = 0;
         }
         if (!empty($prevseenresponse[$partname])) {
             $partscore->penalty = 0;
         }
         $pendingstep->set_behaviour_var('_tries_' . $partname, $currenttries[$partname] + 1);
         if ($this->applypenalties) {
             $pendingstep->set_behaviour_var('_curpenalty_' . $partname, $partscore->penalty);
             $pendingstep->set_behaviour_var('_penalty_' . $partname, min($currentpenalties[$partname] + $partscore->penalty, 1));
             // Cap cumulative penalty at 1.
         } else {
             $pendingstep->set_behaviour_var('_penalty_' . $partname, 0);
         }
         $pendingstep->set_behaviour_var('_rawfraction_' . $partname, $partscore->rawfraction);
         $currentrawfractions[$partname] = $partscore->rawfraction;
         $currentfractions[$partname] = max($partscore->rawfraction - $currentpenalties[$partname], $currentfractions[$partname]);
         // Current fraction never decreases.
         $pendingstep->set_behaviour_var('_fraction_' . $partname, $currentfractions[$partname]);
     }
     if (empty($currentfractions)) {
         $totalfraction = null;
         $overallstate = question_state::$gaveup;
     } else {
         $totalweight = 0;
         $totalfraction = 0;
         foreach ($this->question->get_parts_and_weights() as $index => $weight) {
             $totalweight += $weight;
             if (array_key_exists($index, $currentfractions)) {
                 $totalfraction += $weight * $currentfractions[$index];
             }
         }
         $totalfraction = $totalfraction / $totalweight;
         $allright = true;
         $allwrong = true;
         foreach ($this->question->get_parts_and_weights() as $index => $weight) {
             if (array_key_exists($index, $currentrawfractions)) {
                 $partstate = question_state::graded_state_for_fraction($currentrawfractions[$index]);
                 if ($partstate != question_state::$gradedright) {
                     $allright = false;
                 }
                 if ($partstate != question_state::$gradedwrong) {
                     $allwrong = false;
                 }
             } else {
                 $allright = false;
             }
         }
         if ($allright) {
             $overallstate = question_state::$gradedright;
         } else {
             if ($allwrong) {
                 $overallstate = question_state::$gradedwrong;
             } else {
                 $overallstate = question_state::$gradedpartial;
             }
         }
     }
     return array($totalfraction, $overallstate);
 }
Example #3
0
    public function process_submit(question_attempt_pending_step $pendingstep) {
        if ($this->qa->get_state()->is_finished()) {
            return question_attempt::DISCARD;
        }

        if (!$this->qa->get_question()->is_gradable_response($pendingstep->get_qt_data()) ||
                !$pendingstep->has_behaviour_var('certainty')) {
            $pendingstep->set_state(question_state::$invalid);
            return question_attempt::KEEP;
        }

        return $this->do_grading($pendingstep, $pendingstep);
    }
 public function process_action(question_attempt_pending_step $pendingstep)
 {
     $result = null;
     // Process hint button press.
     foreach ($this->question->hints_available_for_student($pendingstep->get_qt_data()) as $hintkey) {
         $hintkey = $this->adjust_hintkey($hintkey);
         if ($pendingstep->has_behaviour_var($hintkey . 'btn')) {
             $result = $this->process_hint($pendingstep, $hintkey);
         }
     }
     // Proces all actions.
     if ($result === null) {
         $result = parent::process_action($pendingstep);
     }
     // Compute variables to show question it should render it's hint buttons.
     if (!$this->qa->get_state()->is_finished()) {
         $pendingstep->set_behaviour_var('_nonresp_hintbtns', true);
         $response = $pendingstep->get_qt_data();
         if ($this->question->is_complete_response($response)) {
             $pendingstep->set_behaviour_var('_resp_hintbtns', true);
         }
     }
     return $result;
 }
 protected function grade_response(question_attempt_pending_step $pendingstep, $isprecheck)
 {
     $response = $pendingstep->get_qt_data();
     $gradedata = $this->question->grade_response($response, $isprecheck);
     list($fraction, $state) = $gradedata;
     if (count($gradedata) > 2) {
         foreach ($gradedata[2] as $name => $value) {
             $pendingstep->set_qt_var($name, $value);
         }
     }
     return array($fraction, $state);
 }