Esempio n. 1
0
 /**
  * Calculate the user's mark for the question.
  *
  * Must handle exclusions
  *
  * @return integer Status value from marking calculation
  */
 public function calculate_user_mark()
 {
     $returnstatus = null;
     if (is_null($this->useranswer)) {
         $this->error = 'No User Answer';
         $this->qmark = 0;
         return Q_MARKING_UNANSWERABLE;
     }
     if (!isset($this->useranswer['vars'])) {
         $this->error = 'No Variables stored';
         $this->qmark = 0;
         return Q_MARKING_UNCALC_ANSWER;
     }
     if (!is_array($this->useranswer)) {
         $this->useranswer = json_decode($this->useranswer, true);
     }
     if (isset($this->useranswer['uans'])) {
         $return = $this->split_numb_from_unit($this->useranswer['uans']);
         $this->useranswer['uansunit'] = $return[1];
         $this->useranswer['uansnumb'] = $return[0];
     }
     if (isset($this->useranswer['uansunit'])) {
         $this->useranswer['ans']['guessedunits'] = $this->useranswer['uansunit'];
     }
     // Are the units correct?
     $this->useranswer['status']['units'] = $this->are_units_correct($this->useranswer['uansunit']);
     if ($this->useranswer['status']['units'] === false) {
         // We can't match the units so this question must be wrong! However, we need to have a formula and a unit to calculate the feedback
         // so just use the first one!
         foreach ($this->settings['answersexp'] as $unit => $formula) {
             $this->useranswer['ans']['formula_used'] = $formula;
             $this->useranswer['ans']['units_used'] = $unit;
             break;
         }
     } else {
         // Setup the fomula and units for the calculation
         $this->useranswer['ans']['formula_used'] = $this->settings['answersexp'][$this->useranswer['uansunit']];
         $this->useranswer['ans']['units_used'] = $this->useranswer['uansunit'];
     }
     $enhancedcalcType = $this->configObj->get('enhancedcalc_type');
     if (!is_null($enhancedcalcType)) {
         require_once $enhancedcalcType . '.php';
         $name = 'enhancedcalc_' . $enhancedcalcType;
         $enhancedcalcObj = new $name($this->configObj->getbyref('enhancedcalculation'));
     } else {
         require_once 'Rrserve.php';
         $enhancedcalcObj = new EnhancedCalc_Rrserve($this->configObj->getbyref('enhancedcalculation'));
     }
     if (is_array($this->useranswer['vars'])) {
         foreach ($this->useranswer['vars'] as $key => $variablessplit) {
             if ($variablessplit === 'ERROR') {
                 $this->error = "variable {$key} is ERROR";
                 $this->qmark = 0;
                 return Q_MARKING_UNANSWERABLE;
             }
         }
     }
     // Run calculate through the external interface if errors catch exception and indicate its still unmarked.
     try {
         /*
          *
          *  CALCULATE REQURED NUMERIC VALUES
          *
          */
         $this->useranswer['cans'] = $enhancedcalcObj->calculate_correct_ans($this->useranswer['vars'], $this->useranswer['ans']['formula_used']);
     } catch (Exception $e) {
         //TODO: catch different errors "no connection", "unable to evaluate"
         if (stripos($e->getMessage(), 'connect') !== false) {
             $returnstatus = Q_MARKING_UNMARKED;
             // Set to unmarked as there is no connection to R serve.
         } else {
             $returnstatus = Q_MARKING_UNCALC_ANSWER;
             $this->useranswer['status']['error'] = true;
             $this->useranswer['ans']['error'] = $enhancedcalcObj->get_error();
             $this->useranswer['status']['e'] = $e->getCode() . " - " . $e->getMessage();
         }
         $this->useranswer['status']['overall'] = $returnstatus;
         return $returnstatus;
     }
     try {
         if (isset($this->settings['tolerance_full'])) {
             $this->settings['tolerance_full'] = $this->set_blank_to_zero($this->settings['tolerance_full']);
             switch ($this->settings['fulltoltyp']) {
                 case "%":
                     $res = $enhancedcalcObj->calculate_tolerance_percent($this->useranswer['cans'], $this->settings['tolerance_full']);
                     break;
                 case "#":
                     $res = $enhancedcalcObj->calculate_tolerance_absolute($this->useranswer['cans'], $this->settings['tolerance_full']);
                     break;
             }
             $this->useranswer['ans']['tolerance_full'] = $res['tolerance'];
             $this->useranswer['ans']['tolerance_fullans'] = $res['tolerance_ans'];
             $this->useranswer['ans']['tolerance_fullansneg'] = $res['tolerance_ansneg'];
         }
     } catch (Exception $e) {
         //TODO: catch different errors "no connection", "unable to evaluate"
         if (stripos($e->getMessage(), 'connect') !== false) {
             $returnstatus = Q_MARKING_UNMARKED;
             // Set to unmarked as there is no connection to R serve.
         } else {
             $returnstatus = Q_MARKING_UNCALC_FULL_TOLLERANCE;
             $this->useranswer['status']['error'] = true;
             $this->useranswer['ans']['error'] = $enhancedcalcObj->get_error();
             $this->useranswer['status']['e'] = $e->getCode() . " - " . $e->getMessage();
         }
         $this->useranswer['status']['overall'] = $returnstatus;
         return $returnstatus;
     }
     try {
         if (isset($this->settings['tolerance_partial'])) {
             $this->settings['tolerance_partial'] = $this->set_blank_to_zero($this->settings['tolerance_partial']);
             switch ($this->settings['parttoltyp']) {
                 case "%":
                     $res = $enhancedcalcObj->calculate_tolerance_percent($this->useranswer['cans'], $this->settings['tolerance_partial']);
                     break;
                 case "#":
                     $res = $enhancedcalcObj->calculate_tolerance_absolute($this->useranswer['cans'], $this->settings['tolerance_partial']);
                     break;
             }
             $this->useranswer['ans']['tolerance_partial'] = $res['tolerance'];
             $this->useranswer['ans']['tolerance_partialans'] = $res['tolerance_ans'];
             $this->useranswer['ans']['tolerance_partialansneg'] = $res['tolerance_ansneg'];
         }
     } catch (Exception $e) {
         //TODO: catch different errors "no connection", "unable to evaluate"
         if (stripos($e->getMessage(), 'connect') !== false) {
             $returnstatus = Q_MARKING_UNMARKED;
             // Set to unmarked as there is no connection to R serve.
         } else {
             $returnstatus = Q_MARKING_UNCALC_PARTIAL_TOLLERANCE;
             $this->useranswer['status']['error'] = true;
             $this->useranswer['ans']['error'] = $enhancedcalcObj->get_error();
             $this->useranswer['status']['e'] = $e->getCode() . " - " . $e->getMessage();
         }
         $this->useranswer['status']['overall'] = $returnstatus;
         return $returnstatus;
     }
     /*
      *
      * FORMAT CALCULATED ANS
      *
      */
     try {
         if ($this->settings['strictdisplay'] === true and isset($this->settings['dp'])) {
             $function = 'format_number_dp';
             $arg = $this->settings['dp'];
             if ($this->settings['strictzeros'] === true) {
                 $function = 'format_number_dp_strict_zeros';
             }
         } elseif ($this->settings['strictdisplay'] === true and isset($this->settings['sf'])) {
             $function = 'format_number_sf';
             $arg = $this->settings['sf'];
         } else {
             //round to student precision
             $function = 'format_number_to_precision_of_other_number';
             $arg = $this->useranswer['uansnumb'];
         }
         $this->useranswer['cans'] = $enhancedcalcObj->{$function}($this->useranswer['cans'], $arg);
         $this->useranswer['ans']['tolerance_full'] = $enhancedcalcObj->{$function}($this->useranswer['ans']['tolerance_full'], $arg);
         $this->useranswer['ans']['tolerance_fullans'] = $enhancedcalcObj->{$function}($this->useranswer['ans']['tolerance_fullans'], $arg);
         $this->useranswer['ans']['tolerance_fullansneg'] = $enhancedcalcObj->{$function}($this->useranswer['ans']['tolerance_fullansneg'], $arg);
         $this->useranswer['ans']['tolerance_partial'] = $enhancedcalcObj->{$function}($this->useranswer['ans']['tolerance_partial'], $arg);
         $this->useranswer['ans']['tolerance_partialans'] = $enhancedcalcObj->{$function}($this->useranswer['ans']['tolerance_partialans'], $arg);
         $this->useranswer['ans']['tolerance_partialansneg'] = $enhancedcalcObj->{$function}($this->useranswer['ans']['tolerance_partialansneg'], $arg);
     } catch (Exception $e) {
         //TODO: catch different errors "no connection", "unable to evaluate"
         if (stripos($e->getMessage(), 'connect') !== false) {
             $returnstatus = Q_MARKING_UNMARKED;
             // Set to unmarked as there is no connection to R serve.
         } else {
             $returnstatus = Q_MARKING_UNCALC_FORMAT;
             $this->useranswer['status']['error'] = true;
             $this->useranswer['ans']['error'] = $enhancedcalcObj->get_error();
             $this->useranswer['status']['e'] = $e->getCode() . " - " . $e->getMessage();
         }
         $this->useranswer['status']['overall'] = $returnstatus;
         return $returnstatus;
     }
     /*
      *
      * MARKING
      *
      */
     if (!isset($this->useranswer['uansnumb']) or isset($this->useranswer['uansnumb']) and trim($this->useranswer['uansnumb']) == '') {
         // Not answered
         $this->qmark = 0;
         $returnstatus = Q_MARKING_NOTANS;
         $this->useranswer['status']['overall'] = $returnstatus;
         return $returnstatus;
     }
     if ($this->useranswer['status']['units'] === false) {
         // We can't mach the units so this question must be wrong!
         $this->qmark = $this->settings['marks_incorrect'];
         $this->useranswer['status']['exact'] = false;
         $returnstatus = Q_MARKING_WRONG;
         $this->useranswer['status']['overall'] = $returnstatus;
         return $returnstatus;
     }
     try {
         $this->useranswer['status']['exact'] = $enhancedcalcObj->is_useranswer_correct($this->useranswer['uansnumb'], $this->useranswer['cans'], $this->settings['strictdisplay'] !== true);
     } catch (Exception $e) {
         //TODO: catch different errors "no connection", "unable to evaluate"
         if (stripos($e->getMessage(), 'connect') !== false) {
             $returnstatus = Q_MARKING_UNMARKED;
             // Set to unmarked as there is no connection to R serve.
         } else {
             $returnstatus = Q_MARKING_UNCALC_USER_ANSWER;
             $this->useranswer['status']['error'] = true;
             $this->useranswer['ans']['error'] = $enhancedcalcObj->get_error();
             $this->useranswer['status']['e'] = $e->getCode() . " - " . $e->getMessage();
         }
         $this->useranswer['status']['overall'] = $returnstatus;
         return $returnstatus;
     }
     try {
         // Calculate distance from correct if needed
         if ($this->useranswer['status']['exact'] === false) {
             $this->useranswer['cans_dist'] = $enhancedcalcObj->distance_from_correct_answer($this->useranswer['uansnumb'], $this->useranswer['cans']);
         } else {
             $this->useranswer['cans_dist'] = '0';
         }
     } catch (Exception $e) {
         //TODO: catch different errors "no connection", "unable to evaluate"
         if (stripos($e->getMessage(), 'connect') !== false) {
             $returnstatus = Q_MARKING_UNMARKED;
             // Set to unmarked as there is no connection to R serve.
         } else {
             $returnstatus = Q_MARKING_UNCALC_DIST_FROM_ANSWER;
             $this->useranswer['status']['error'] = true;
             $this->useranswer['ans']['error'] = $enhancedcalcObj->get_error();
             $this->useranswer['status']['e'] = $e->getCode() . " - " . $e->getMessage();
         }
         $this->useranswer['status']['overall'] = $returnstatus;
         return $returnstatus;
     }
     if ($this->useranswer['status']['exact'] === false) {
         try {
             $this->useranswer['status']['tolerance_full'] = $enhancedcalcObj->is_useranswer_within_tolerance($this->useranswer['uansnumb'], $this->useranswer['ans']['tolerance_fullansneg'], $this->useranswer['ans']['tolerance_fullans']);
         } catch (Exception $e) {
             //TODO: catch different errors "no connection", "unable to evaluate"
             if (stripos($e->getMessage(), 'connect') !== false) {
                 $returnstatus = Q_MARKING_UNMARKED;
                 // Set to unmarked as there is no connection to R serve.
             } else {
                 $returnstatus = Q_MARKING_UNCALC_WITHIN_FULL_TOLERANCE;
                 $this->useranswer['status']['error'] = true;
                 $this->useranswer['ans']['error'] = $enhancedcalcObj->get_error();
                 $this->useranswer['status']['e'] = $e->getCode() . " - " . $e->getMessage();
             }
             $this->useranswer['status']['overall'] = $returnstatus;
             return $returnstatus;
         }
         if ($this->useranswer['status']['tolerance_full'] === false) {
             try {
                 $this->useranswer['status']['tolerance_partial'] = $enhancedcalcObj->is_useranswer_within_tolerance($this->useranswer['uansnumb'], $this->useranswer['ans']['tolerance_partialansneg'], $this->useranswer['ans']['tolerance_partialans']);
             } catch (Exception $e) {
                 //TODO: catch different errors "no connection", "unable to evaluate"
                 if (stripos($e->getMessage(), 'connect') !== false) {
                     $returnstatus = Q_MARKING_UNMARKED;
                     // Set to unmarked as there is no connection to R serve.
                 } else {
                     $returnstatus = Q_MARKING_UNCALC_WITHIN_PARTIAL_TOLERANCE;
                     $this->useranswer['status']['error'] = true;
                     $this->useranswer['ans']['error'] = $enhancedcalcObj->get_error();
                     $this->useranswer['status']['e'] = $e->getCode() . " - " . $e->getMessage();
                 }
                 $this->useranswer['status']['overall'] = $returnstatus;
                 return $returnstatus;
             }
         }
     } else {
         $this->useranswer['status']['tolerance_partial'] = true;
         $this->useranswer['status']['tolerance_full'] = true;
     }
     try {
         // Strict dp marking
         if ($this->is_strict_dp_enabled()) {
             if ($this->is_strict_dp_strictzeros_enabled()) {
                 $this->useranswer['status']['strictdp'] = $enhancedcalcObj->is_useranswer_correct_decimal_places_strictzeros($this->useranswer['uansnumb'], $this->settings['dp']);
             } else {
                 $this->useranswer['status']['strictdp'] = $enhancedcalcObj->is_useranswer_correct_decimal_places($this->useranswer['uansnumb'], $this->settings['dp']);
             }
             if ($this->useranswer['status']['strictdp'] === false) {
                 $this->qmark = $this->settings['marks_incorrect'];
                 $returnstatus = Q_MARKING_WRONG;
                 $this->useranswer['status']['overall'] = $returnstatus;
                 return $returnstatus;
             }
         }
     } catch (Exception $e) {
         //TODO: catch different errors "no connection", "unable to evaluate"
         if (stripos($e->getMessage(), 'connect') !== false) {
             $returnstatus = Q_MARKING_UNMARKED;
             // Set to unmarked as there is no connection to R serve.
         } else {
             $returnstatus = Q_MARKING_UNCALC_STRICT_DP_CHECK;
             $this->useranswer['status']['error'] = true;
             $this->useranswer['ans']['error'] = $enhancedcalcObj->get_error();
             $this->useranswer['status']['e'] = $e->getCode() . " - " . $e->getMessage();
         }
         $this->useranswer['status']['overall'] = $returnstatus;
         return $returnstatus;
     }
     try {
         // Sheck for strict sf
         if ($this->is_strict_sf_enabled()) {
             $this->useranswer['status']['strictsf'] = $enhancedcalcObj->is_useranswer_within_significant_figures($this->useranswer['uansnumb'], $this->settings['sf']);
             if ($this->useranswer['status']['strictsf'] === false) {
                 $this->qmark = $this->settings['marks_incorrect'];
                 $returnstatus = Q_MARKING_WRONG;
                 $this->useranswer['status']['overall'] = $returnstatus;
                 return $returnstatus;
             }
         }
         // Assume its wrong wrong !!
         $returnstatus = Q_MARKING_WRONG;
         $this->qmark = $this->settings['marks_incorrect'];
         // Part tolerance range
         if ($this->is_user_ans_within_partial_tolerance()) {
             $this->qmark = $this->settings['marks_partial'];
             $returnstatus = Q_MARKING_PART_TOL;
         }
         // Full tolerance range
         if ($this->is_user_ans_within_fullmark_tolerance()) {
             $this->qmark = $this->settings['marks_correct'];
             $returnstatus = Q_MARKING_FULL_TOL;
         }
         // Exact answer
         if ($this->is_user_ans_correct()) {
             $this->qmark = $this->settings['marks_correct'];
             $returnstatus = Q_MARKING_EXACT;
         }
         // Remove marks for incorrect unit
         if (isset($this->settings['unit_marks']) and !($this->settings['unit_marks'] == 0 or $this->settings['unit_marks'] == 'invalidate') and $this->useranswer['status']['units'] !== true) {
             $this->qmark = $this->qmark - $this->settings['unit_marks'];
             $returnstatus = Q_MARKING_PART_UNITS_WRONG;
         }
         $this->useranswer['status']['overall'] = $returnstatus;
     } catch (Exception $e) {
         //TODO: catch different errors "no connection", "unable to evaluate"
         if (stripos($e->getMessage(), 'connect') !== false) {
             $returnstatus = Q_MARKING_UNMARKED;
             // Set to unmarked as there is no connection to R serve.
         } else {
             $returnstatus = Q_MARKING_ERROR;
             $this->useranswer['status']['error'] = true;
             $this->useranswer['ans']['error'] = $enhancedcalcObj->get_error();
             $this->useranswer['status']['e'] = $e->getCode() . " - " . $e->getMessage() . " - " . $e->getTraceAsString();
         }
         $this->useranswer['status']['overall'] = $returnstatus;
         return $returnstatus;
     }
     return $returnstatus;
 }