public function feedback(question_attempt $qa, question_display_options $options) { // Try to find the last graded step. $gradedstep = $this->get_graded_step($qa); if (is_null($gradedstep) || $qa->get_max_mark() == 0 || $options->marks < question_display_options::MARK_AND_MAX) { return ''; } // Display the grading details from the last graded state $mark = new stdClass(); $mark->max = $qa->format_max_mark($options->markdp); $actualmark = $gradedstep->get_fraction() * $qa->get_max_mark(); $mark->cur = format_float($actualmark, $options->markdp); $rawmark = $gradedstep->get_behaviour_var('_rawfraction') * $qa->get_max_mark(); $mark->raw = format_float($rawmark, $options->markdp); // let student know wether the answer was correct if ($qa->get_state()->is_commented()) { $class = $qa->get_state()->get_feedback_class(); } else { $class = question_state::graded_state_for_fraction($gradedstep->get_behaviour_var('_rawfraction'))->get_feedback_class(); } $gradingdetails = get_string('gradingdetails', 'qbehaviour_adaptive', $mark); $gradingdetails .= $this->penalty_info($qa, $mark, $options); $output = ''; $output .= html_writer::tag('div', get_string($class, 'question'), array('class' => 'correctness ' . $class)); $output .= html_writer::tag('div', $gradingdetails, array('class' => 'gradingdetails')); return $output; }
public function grade_response(array $response) { $fraction = 0; list($numright, $total) = $this->get_num_parts_right($response); $numwrong = $this->get_num_selected_choices($response) - $numright; $numcorrect = $this->get_num_correct_choices(); if ($numwrong == 0 && $numcorrect == $numright) { $fraction = 1; } $state = question_state::graded_state_for_fraction($fraction); return array($fraction, $state); }
public function correct_response(question_attempt $qa) { $result = ""; $question = $qa->get_question(); if ($question->shownumcorrect) { foreach ($question->get_order($qa) as $ans_number => $ans_id) { $answer = $question->answers[$ans_id]; if (question_state::graded_state_for_fraction($answer->fraction) == question_state::$gradedright) { $result = get_string('correctansweris', 'qtype_multichoice', qtype_omeromultichoice_base_renderer::number_answer($ans_number, $question->answernumbering)); } } } return $result; }
public function get_state_string($showcorrectness) { $laststep = $this->qa->get_last_step(); if ($laststep->has_behaviour_var('_try')) { $state = question_state::graded_state_for_fraction($laststep->get_behaviour_var('_rawfraction')); return $state->default_string(true); } $state = $this->qa->get_state(); if ($state == question_state::$todo) { return get_string('notcomplete', 'qbehaviour_adaptive'); } else { return parent::get_state_string($showcorrectness); } }
/** * Find the corresponding choice id of the first correct answer of a shortanswer question. * choice is added to the randomsamatch question if it doesn't already exist. * @param object $wrappedquestion short answer question. * @return int correct choice id. */ public function find_right_answer($wrappedquestion) { // We only take into account *one* (the first) correct answer. while ($answer = array_shift($wrappedquestion->answers)) { if (!question_state::graded_state_for_fraction($answer->fraction)->is_incorrect()) { // Store this answer as a choice, only if this is a new one. $key = array_search($answer->answer, $this->choices); if ($key === false) { $key = $answer->id; $this->choices[$key] = $answer->answer; } return $key; } } // We should never get there. throw new coding_exception('shortanswerquestionwithoutrightanswer', $wrappedquestion->id); }
public function get_correct_answer() { foreach ($this->question->get_answers() as $answer) { $state = question_state::graded_state_for_fraction($answer->fraction); if ($state == question_state::$gradedright) { return $answer; } } return null; }
/** * Create a question_attempt_step from records loaded from the database. * @param Iterator $records Raw records loaded from the database. * @param int $stepid The id of the records to extract. * @param string $qtype The question type of which this is an attempt. * If not given, each record must include a qtype field. * @return question_attempt_step The newly constructed question_attempt_step. */ public static function load_from_records($records, $attemptstepid, $qtype = null) { $currentrec = $records->current(); while ($currentrec->attemptstepid != $attemptstepid) { $records->next(); if (!$records->valid()) { throw new coding_exception('Question attempt step ' . $attemptstepid . ' not found in the database.'); } $currentrec = $records->current(); } $record = $currentrec; $contextid = null; $data = array(); while ($currentrec && $currentrec->attemptstepid == $attemptstepid) { if (!is_null($currentrec->name)) { $data[$currentrec->name] = $currentrec->value; } $records->next(); if ($records->valid()) { $currentrec = $records->current(); } else { $currentrec = false; } } $step = new question_attempt_step_read_only($data, $record->timecreated, $record->userid); $step->state = question_state::get($record->state); $step->id = $record->attemptstepid; if (!is_null($record->fraction)) { $step->fraction = $record->fraction + 0; } // This next chunk of code requires getting $contextid and $qtype here. // Somehow, we need to get that information to this point by modifying // all the paths by which this method can be called. // Can we only return files when it's possible? Should there be some kind of warning? if (is_null($qtype)) { $qtype = $record->qtype; } foreach (question_bank::get_qtype($qtype)->response_file_areas() as $area) { if (empty($step->data[$area])) { continue; } $step->data[$area] = new question_file_loader($step, $area, $step->data[$area], $record->contextid); } return $step; }
protected function get_num_correct_choices($questiondata) { $numright = 0; foreach ($questiondata->options->answers as $answer) { if (!question_state::graded_state_for_fraction($answer->fraction)->is_incorrect()) { $numright += 1; } } return $numright; }
/** * Call local or remote execute function. Evaluation of junit output is done. Grade is calculated and feedback * generated. * * @param array $response the response of the student * @return array $fraction fraction of the grade. If the max grade is 10 then fraction can be for example 2 (10/5 = * 2 indicating that from 10 points the student achieved 5). */ public function grade_response(array $response) { global $CFG, $DB; if ($this->questionattemptid === null) { // we need the attempt id throw new Exception('qtype_javaunittest: grade_response, no questionattemptid'); } $fraction = 0; $feedback = ''; $cfg_plugin = get_config('qtype_javaunittest'); if (empty($cfg_plugin->remoteserver)) { $ret = $this->local_execute($response); } else { $ret = $this->remote_execute($response); } if ($ret['error']) { if ($ret['errortype'] == 'COMPILE_STUDENT_ERROR') { $feedback = get_string('CE', 'qtype_javaunittest') . '<br><pre>' . htmlspecialchars($ret['compileroutput']) . '</pre>'; } else { if ($ret['errortype'] == 'COMPILE_TESTFILE_ERROR') { $feedback = get_string('JE', 'qtype_javaunittest'); } else { if ($ret['errortype'] == 'TIMEOUT_RUNNING') { $feedback = get_string('TO', 'qtype_javaunittest'); } else { if ($ret['errortype'] == 'REMOTE_SERVER_ERROR') { $feedback = htmlspecialchars('REMOTE_SERVER_ERROR: ' . $ret['message']); } } } } } else { // the JUnit-execution-output returns always a String in the first line // e.g. "...F", // which means that 1 out of 3 test cases didn't pass the JUnit test // In the second line it says "Time ..." $output = $ret['junitoutput']; $junitstart = strrpos($output, 'JUnit version'); $matches = array(); $found = preg_match('@JUnit version [\\d\\.]*\\n([\\.EF]+)\\n@', $output, $matches, 0, $junitstart); if (!$found) { $feedback = get_string('JE', 'qtype_javaunittest'); } else { // count failures and errors $numtests = substr_count($matches[1], '.'); $numfailures = substr_count($matches[1], 'F'); $numerrors = substr_count($matches[1], 'E'); $totalerrors = $numfailures + $numerrors; $fraction = 1 - round($totalerrors / $numtests, 2); // generate feedback if ($this->feedbacklevel >= FEEDBACK_ONLY_TIMES) { $feedback = get_string('compiling', 'qtype_javaunittest', round($ret['compiletime'], 1)); $feedback .= "<br>\n"; $feedback .= get_string('running', 'qtype_javaunittest', round($ret['testruntime'], 1)); $feedback .= "<br>\n"; $feedback .= "<br>\n"; } if ($this->feedbacklevel >= FEEDBACK_TIMES_COUNT_OF_TESTS) { $feedback .= "Tests: " . $numtests . "<br>\n"; $feedback .= "Failures: " . $numfailures . "<br>\n"; $feedback .= "Errors: " . $numerrors . "<br>\n"; $feedback .= "<br>\n"; $feedback .= "<br>\n"; } if ($this->feedbacklevel == FEEDBACK_ALL_EXCEPT_STACKTRACE) { $matches = array(); $found = preg_match('@(.*)There (were|was) (\\d*) failure(s?):\\n@s', $output, $matches); if ($found) { $feedback .= '<pre>' . htmlspecialchars($matches[1]) . '</pre>'; $feedback .= "<br>\n"; } else { $feedback .= '<pre>' . htmlspecialchars($output) . '</pre>'; $feedback .= "<br>\n"; } $feedback .= "<br>\n"; } // search for common throwables, ordered primary by package, secundary by alphabet if (strpos($output, 'java.io.IOException') !== false) { $feedback .= get_string('ioexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.io.FileNotFoundException') !== false) { $feedback .= get_string('filenotfoundexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.ArrayIndexOutOfBoundsException') !== false) { $feedback .= get_string('arrayindexoutofboundexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.ClassCastException') !== false) { $feedback .= get_string('classcastexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.NegativeArraySizeException') !== false) { $feedback .= get_string('negativearraysizeexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.NullPointerException') !== false) { $feedback .= get_string('nullpointerexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.OutOfMemoryError') !== false) { $feedback .= get_string('outofmemoryerror', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.StackOverflowError') !== false) { $feedback .= get_string('stackoverflowerror', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.StringIndexOutOfBoundsException') !== false) { $feedback .= get_string('stringindexoutofboundexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.nio.BufferOverflowException') !== false) { $feedback .= get_string('bufferoverflowexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.nio.BufferUnderflowException') !== false) { $feedback .= get_string('bufferunderflowexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.security.AccessControlException') !== false) { $feedback .= get_string('accesscontrolexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } // append feedback phrase (wrong / [partially] corrent answer phrase) if ($numtests > 0 && $totalerrors == 0) { $feedback .= get_string('CA', 'qtype_javaunittest'); $feedback .= "<br>\n"; } else { if ($numtests > 0 && $numtests == $totalerrors) { $feedback .= get_string('WA', 'qtype_javaunittest'); $feedback .= "<br>\n"; } else { if ($numtests > 0 && $totalerrors != 0) { $feedback .= get_string('PCA', 'qtype_javaunittest'); $feedback .= "<br>\n"; } } } } } // save feedback $cur_feedback = $DB->get_record('qtype_javaunittest_feedback', array('questionattemptid' => $this->questionattemptid)); $db_feedback = new stdClass(); $db_feedback->questionattemptid = $this->questionattemptid; $db_feedback->feedback = $feedback; if ($cur_feedback) { $db_feedback->id = $cur_feedback->id; $DB->update_record('qtype_javaunittest_feedback', $db_feedback); } else { $DB->insert_record('qtype_javaunittest_feedback', $db_feedback); } return array($fraction, question_state::graded_state_for_fraction($fraction)); }
public function grade_response(array $response) { $this->update_current_response($response); $countcorrect = 0; $countanswers = 0; $correctresponse = $this->correctresponse; $currentresponse = $this->currentresponse; foreach ($currentresponse as $position => $answerid) { if ($correctresponse[$position] == $answerid) { $countcorrect++; } $countanswers++; } if ($countanswers == 0) { $fraction = 0; } else { $fraction = $countcorrect / $countanswers; } return array($fraction, question_state::graded_state_for_fraction($fraction)); }
/** * Call local or remote execute function. Evaluation of junit output is done. Grade is calculated and feedback * generated. * * @param array $response the response of the student * @return array $fraction fraction of the grade. If the max grade is 10 then fraction can be for example 2 (10/5 = * 2 indicating that from 10 points the student achieved 5). */ public function grade_response(array $response) { global $CFG, $DB; if ($this->questionattemptid === null) { // we need the attempt id throw new Exception('qtype_javaunittest: grade_response, no questionattemptid'); } $weight_style; if ($this->auditlevel == AUDIT_VALUE_10) { $weight_style = 0.1; } else { if ($this->auditlevel == AUDIT_VALUE_20) { $weight_style = 0.2; } else { if ($this->auditlevel == AUDIT_VALUE_30) { $weight_style = 0.3; } else { if ($this->auditlevel == AUDIT_VALUE_40) { $weight_style = 0.4; } else { if ($this->auditlevel == AUDIT_VALUE_50) { $weight_style = 0.5; } else { if ($this->auditlevel == AUDIT_VALUE_60) { $weight_style = 0.6; } else { if ($this->auditlevel == AUDIT_VALUE_70) { $weight_style = 0.7; } else { if ($this->auditlevel == AUDIT_VALUE_80) { $weight_style = 0.8; } else { if ($this->auditlevel == AUDIT_VALUE_90) { $weight_style = 0.9; } } } } } } } } } /*else{ $weight_style = 1.0 }*/ $fraction = 0; $fraction_code = 0; #$weight_style = 0.3; #$weight_style = $auditlevel; $weight_unittests = 1.0 - $weight_style; $num_errors_style = 0; $feedback = ''; $cfg_plugin = get_config('qtype_javaunittest'); if (empty($cfg_plugin->remoteserver)) { $ret = $this->local_execute($response); } else { $ret = $this->remote_execute($response); } $num_errors_style = substr_count($ret['auditoutput'], '.java:'); $max_errors_style = 6; if ($num_errors_style < 0) { $num_errors_style = 0; } if ($num_errors_style > $max_errors_style) { $num_errors_style = $max_errors_style; } $fraction_style = ($max_errors_style - $num_errors_style) * 1.0 / $max_errors_style; if ($ret['error']) { if ($ret['errortype'] == 'COMPILE_STUDENT_ERROR') { $feedback = get_string('CE', 'qtype_javaunittest') . '<br><pre>' . htmlspecialchars($ret['compileroutput']) . '</pre>'; } else { if ($ret['errortype'] == 'COMPILE_TESTFILE_ERROR') { $feedback = get_string('JE', 'qtype_javaunittest'); $output = $ret['compileroutput']; $feedback .= '<br/>'; $feedback .= '<div style="border:1px solid #000;">'; $feedback .= '<b><font color="red">Error in Unit Test Definition</font></b>'; $feedback .= '</div><br/>'; $feedback .= '<font color="#0000A0"><b>Details of the execution:</b></font><br/>'; $feedback .= '<pre>' . $output . '</pre>'; $feedback .= '<br/>'; } else { if ($ret['errortype'] == 'TIMEOUT_RUNNING') { $feedback = get_string('TO', 'qtype_javaunittest'); } else { if ($ret['errortype'] == 'REMOTE_SERVER_ERROR') { $feedback = htmlspecialchars('REMOTE_SERVER_ERROR: ' . $ret['message']); } } } } } else { // the JUnit-execution-output returns always a String in the first line // e.g. "...F", // which means that 1 out of 3 test cases didn't pass the JUnit test // In the second line it says "Time ..." $output = $ret['junitoutput']; $junitstart = strrpos($output, 'JUnit version'); $matches = array(); $found = preg_match('@JUnit version [\\d\\.]*\\n([\\.EF]+)\\n@', $output, $matches, 0, $junitstart); if (!$found) { $feedback = get_string('JE', 'qtype_javaunittest'); $feedback .= '<br/>'; $feedback .= '<div style="border:1px solid #000;">'; $feedback .= '<b><font color="red">Error in Unit Test Definition</font></b>'; $feedback .= '</div><br/>'; $feedback .= '<font color="#0000A0"><b>Details of the execution:</b></font><br/>'; $feedback .= '<pre>' . $ret['compileroutput'] . '</pre>'; $feedback .= '<br/>'; } else { // count failures and errors $numtests = substr_count($matches[1], '.'); $numfailures = substr_count($matches[1], 'F'); $numerrors = substr_count($matches[1], 'E'); $totalerrors = $numfailures + $numerrors; $fraction_code = 1 - round($totalerrors / $numtests, 2); $fraction = $fraction_code * $weight_unittests + $fraction_style * $weight_style; // generate feedback if ($this->feedbacklevel >= FEEDBACK_ONLY_TIMES) { $feedback = get_string('compiling', 'qtype_javaunittest', round($ret['compiletime'], 1)); $feedback .= "<br>\n"; $feedback .= get_string('running', 'qtype_javaunittest', round($ret['testruntime'], 1)); $feedback .= "<br>\n"; } if ($this->feedbacklevel >= FEEDBACK_TIMES_COUNT_OF_TESTS) { #$feedback .= "Tests: " . $numtests . "<br>\n"; #$feedback .= "Failures: " . $numfailures . "<br>\n"; #$feedback .= "Errors: " . $numerrors . "<br>\n"; $feedback .= "<br>\n"; } if ($this->feedbacklevel == FEEDBACK_ALL_EXCEPT_STACKTRACE) { $matches = array(); $found = preg_match('@(.*)There (were|was) (\\d*) failure(s?):\\n@s', $output, $matches); if ($found) { $feedback .= '<pre>' . htmlspecialchars($matches[1]) . '</pre>'; $feedback .= "<br>\n"; } else { $feedback .= '<pre>' . htmlspecialchars($output) . '</pre>'; $feedback .= "<br>\n"; } } if ($this->feedbacklevel == FEEDBACK_ALL) { $feedback .= '<font color="#5F04B4"><b>'; if ($numtests > 0 && $totalerrors == 0 && $num_errors_style == 0) { $feedback .= get_string('CA', 'qtype_javaunittest'); } else { if ($numtests > 0 && ($totalerrors > 0 || $num_errors_style > 0)) { $feedback .= get_string('PCA', 'qtype_javaunittest'); } else { if ($numtests > 0 && ($numtests >= $totalerrors && $num_errors_style >= $max_errors_style)) { $feedback .= get_string('WA', 'qtype_javaunittest'); } } } $feedback .= "</b></font>\n"; $feedback .= "<br>\n"; $feedback .= '<font color="#0000A0">Global grade for the current question: <b>' . $fraction * 100 . '% / ' . 100 . '%</b></font><br/><br/>'; $feedback .= "<br>\n"; $outtext = preg_replace('/at(.*)\\)\\n/', '', $output); $outtext = htmlspecialchars($outtext); $outtext = preg_replace('/junit(.*)\\n/', '<br/><b>junit$1</b><br/>', $outtext); $output_audit = preg_replace('/at(.*)\\)\\n/', '', $output); $output_audit = htmlspecialchars($ret['auditoutput']); #$cwd = getcwd(); #$feedback .= 'cwd=' . getcwd() . '<br/>'; #$feedback .= 'dirroot=' . $CFG->dirroot . '<br/>'; #$feedback .= 'wwwroot=' . $CFG->wwwroot . '<br/>'; $feedback .= '<div style="border:1px solid #000;">'; $feedback .= '<b><font color="blue">Results of Code Audit</font></b>'; $feedback .= '</div><br/>'; $feedback .= '<font color="#0000A0">Value of Code Audit in question grade: <b>' . $weight_style * 100 . '%</b></font><br/>'; $feedback .= '<font color="#0000A0">The first <b>' . $max_errors_style . '</b> errors give bad points</font><br/>'; $feedback .= '<font color="#0000A0">Number of errors made by the student: <b>' . $num_errors_style . '</b></font><br/>'; $feedback .= '<font color="#0000A0">Grade for section Code Audit: <b>' . $fraction_style * $weight_style * 100 . '% / ' . $weight_style * 100 . '%</b></font><br/><br/>'; $feedback .= '<font color="#0000A0"><b>Details of audit hereafter:</b></font><br/>'; $feedback .= '<pre>' . $output_audit . '</pre>'; $feedback .= '<br/>'; $feedback .= '<div style="border:1px solid #000;">'; $feedback .= '<b><font color="blue">Results of Unit Tests</font></b>'; $feedback .= '</div><br/>'; $feedback .= '<font color="#0000A0">Number of evaluated tests: <b>' . $numtests . '</b></font><br/>'; $feedback .= '<font color="#0000A0">Number of observed failures: <b>' . $numfailures . ' / ' . $numtests . '</b></font><br/>'; $feedback .= '<font color="#0000A0">Number of observed errors: <b>' . $numerrors . ' / ' . $numtests . '</b></font><br/>'; $feedback .= '<font color="#0000A0">Grade for section Unit Tests: <b>' . $fraction_code * $weight_unittests * 100 . '% / ' . $weight_unittests * 100 . '%</b></font><br/><br/>'; $feedback .= '<font color="#0000A0"><b>Details of unit tests hereafter:</b></font><br/>'; $feedback .= '<pre>' . $outtext . '</pre>'; $feedback .= "<br>\n"; } // search for common throwables, by package, by alphabet if (strpos($output, 'java.io.IOException') !== false) { $feedback .= get_string('ioexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.io.FileNotFoundException') !== false) { $feedback .= get_string('filenotfoundexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.ArrayIndexOutOfBoundsException') !== false) { $feedback .= get_string('arrayindexoutofboundexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.ClassCastException') !== false) { $feedback .= get_string('classcastexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.NegativeArraySizeException') !== false) { $feedback .= get_string('negativearraysizeexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.NullPointerException') !== false) { $feedback .= get_string('nullpointerexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.OutOfMemoryError') !== false) { $feedback .= get_string('outofmemoryerror', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.StackOverflowError') !== false) { $feedback .= get_string('stackoverflowerror', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.lang.StringIndexOutOfBoundsException') !== false) { $feedback .= get_string('stringindexoutofboundexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.nio.BufferOverflowException') !== false) { $feedback .= get_string('bufferoverflowexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.nio.BufferUnderflowException') !== false) { $feedback .= get_string('bufferunderflowexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } if (strpos($output, 'java.security.AccessControlException') !== false) { $feedback .= get_string('accesscontrolexception', 'qtype_javaunittest'); $feedback .= "<br>\n<br>\n"; } // append feedback phrase (wrong / [partially] corrent answer phrase) if ($numtests > 0 && $totalerrors == 0 && $num_errors_style == 0) { $feedback .= get_string('CA', 'qtype_javaunittest'); } else { if ($numtests > 0 && ($totalerrors != 0 || $num_errors_style != 0)) { $feedback .= get_string('PCA', 'qtype_javaunittest'); } else { if ($numtest > 0 && ($numtests >= $totalerrors && $num_errors_style >= $max_errors_style)) { $feedback .= get_string('WA', 'qtype_javaunittest'); } } } $feedback .= "<br>\n"; } } // save feedback $cur_feedback = $DB->get_record('qtype_javaunittest_feedback', array('questionattemptid' => $this->questionattemptid)); $db_feedback = new stdClass(); $db_feedback->questionattemptid = $this->questionattemptid; $db_feedback->feedback = $feedback; if ($cur_feedback) { $db_feedback->id = $cur_feedback->id; $DB->update_record('qtype_javaunittest_feedback', $db_feedback); } else { $DB->insert_record('qtype_javaunittest_feedback', $db_feedback); } return array($fraction, question_state::graded_state_for_fraction($fraction)); }
/** * Return an appropriate icon (green tick, red cross, etc.) for a grade. * @param float $fraction grade on a scale 0..1. * @return string html fragment. */ protected function icon_for_fraction($fraction) { global $OUTPUT; $feedbackclass = question_state::graded_state_for_fraction($fraction)->get_feedback_class(); return $OUTPUT->pix_icon('i/grade_' . $feedbackclass, get_string($feedbackclass, 'question'), 'moodle', array('class' => 'icon')); }
public function grade_response(array $response) { $response = $this->discard_duplicates($response); list($right, $total) = $this->get_num_parts_right($response); $this->fraction = $right / $total; $grade = array($this->fraction, question_state::graded_state_for_fraction($this->fraction)); return $grade; }
/** * Return an appropriate icon (green tick, red cross, etc.) for a grade. * @param float $fraction grade on a scale 0..1. * @return string html fragment. */ protected function icon_for_fraction($fraction) { global $OUTPUT; $state = question_state::graded_state_for_fraction($fraction); if ($state == question_state::$gradedright) { $icon = 'i/tick_green_big'; } else if ($state == question_state::$gradedpartial) { $icon = 'i/tick_amber_big'; } else { $icon = 'i/cross_red_big'; } return $OUTPUT->pix_icon($icon, get_string($state->get_feedback_class(), 'question'), 'moodle', array('class' => 'icon')); }
/** * Render the feedback pop-up contents. * * @param question_graded_automatically $subq the subquestion. * @param float $fraction the mark the student got. null if this subq was not answered. * @param string $feedbacktext the feedback text, already processed with format_text etc. * @param string $rightanswer the right answer, already processed with format_text etc. * @param question_display_options $options the display options. * @return string the HTML for the feedback popup. */ protected function feedback_popup(question_graded_automatically $subq, $fraction, $feedbacktext, $rightanswer, question_display_options $options) { if (!$options->feedback) { return ''; } $feedback = array(); if ($options->correctness) { if (is_null($fraction)) { $state = question_state::$gaveup; } else { $state = question_state::graded_state_for_fraction($fraction); } $feedback[] = $state->default_string(true); } if ($options->rightanswer) { $feedback[] = get_string('correctansweris', 'qtype_shortanswer', $rightanswer); } $subfraction = ''; if ($options->marks >= question_display_options::MARK_AND_MAX && $subq->maxmark > 0) { $a = new stdClass(); $a->mark = format_float($fraction * $subq->maxmark, $options->markdp); $a->max = format_float($subq->maxmark, $options->markdp); $feedback[] = get_string('markoutofmax', 'question', $a); } return html_writer::tag('span', implode('<br />', $feedback), array('class' => 'feedbackspan accesshide')); }
public function test_graded_state_for_fraction() { $this->assertEquals(question_state::$gradedwrong, question_state::graded_state_for_fraction(-1)); $this->assertEquals(question_state::$gradedwrong, question_state::graded_state_for_fraction(0)); $this->assertEquals(question_state::$gradedpartial, question_state::graded_state_for_fraction(1.0E-6)); $this->assertEquals(question_state::$gradedpartial, question_state::graded_state_for_fraction(0.999999)); $this->assertEquals(question_state::$gradedright, question_state::graded_state_for_fraction(1)); }
/** * @param string $colname the name of the column. * @param object $attempt the row of data - see the SQL in display() in * mod/quiz/report/overview/report.php to see what fields are present, * and what they are called. * @return string the contents of the cell. */ public function other_cols($colname, $attempt) { if (!preg_match('/^qsgrade(\\d+)$/', $colname, $matches)) { return null; } $slot = $matches[1]; $question = $this->questions[$slot]; if (!isset($this->lateststeps[$attempt->usageid][$slot])) { return '-'; } $stepdata = $this->lateststeps[$attempt->usageid][$slot]; $state = question_state::get($stepdata->state); if ($question->maxmark == 0) { $grade = '-'; } else { if (is_null($stepdata->fraction)) { if ($state == question_state::$needsgrading) { $grade = get_string('requiresgrading', 'question'); } else { $grade = '-'; } } else { $grade = quiz_rescale_grade($stepdata->fraction * $question->maxmark, $this->quiz, 'question'); } } if ($this->is_downloading()) { return $grade; } if (isset($this->regradedqs[$attempt->usageid][$slot])) { $gradefromdb = $grade; $newgrade = quiz_rescale_grade($this->regradedqs[$attempt->usageid][$slot]->newfraction * $question->maxmark, $this->quiz, 'question'); $oldgrade = quiz_rescale_grade($this->regradedqs[$attempt->usageid][$slot]->oldfraction * $question->maxmark, $this->quiz, 'question'); $grade = html_writer::tag('del', $oldgrade) . '/' . html_writer::empty_tag('br') . $newgrade; } return $this->make_review_link($grade, $attempt, $slot); }
protected function get_contains_subq_status(question_state $state) { return new question_pattern_expectation('~' . preg_quote($state->default_string(true), '~') . '<br />~'); }
public function grade_response(array $response) { if ($this->has_separate_unit_field()) { $selectedunit = $response['unit']; } else { $selectedunit = null; } list($value, $unit, $multiplier) = $this->ap->apply_units($response['answer'], $selectedunit); $answer = $this->get_matching_answer($value, $multiplier); if (!$answer) { return array(0, question_state::$gradedwrong); } $fraction = $this->apply_unit_penalty($answer->fraction, $answer->unitisright); return array($fraction, question_state::graded_state_for_fraction($fraction)); }
public function grade_response(array $response) { $fraction = 0; foreach ($this->order as $key => $ansid) { if (!empty($response[$this->field($key)])) { $fraction += $this->answers[$ansid]->fraction; } } $fraction = min(max(0, $fraction), 1.0); return array($fraction, question_state::graded_state_for_fraction($fraction)); }
/** * Get the SQL needed to test that question_attempt_steps.state is in a * state corresponding to $summarystate. * @param string $summarystate one of * inprogress, needsgrading, manuallygraded or autograded * @param bool $equal if false, do a NOT IN test. Default true. * @return string SQL fragment. */ public function in_summary_state_test($summarystate, $equal = true, $prefix = 'summarystates') { $states = question_state::get_all_for_summary_state($summarystate); return $this->db->get_in_or_equal(array_map('strval', $states), SQL_PARAMS_NAMED, $prefix, $equal); }
public function grade_response(array $response) { list($right, $total) = $this->get_num_parts_right($response); $fraction = $right / $total; return array($fraction, question_state::graded_state_for_fraction($fraction)); }
/** * Get the current mark details for a particular part. * @param string $index the part index. * @return qbehaviour_adaptivemultipart_mark_details the marks information. */ public function get_part_mark_details($index) { $step = $this->qa->get_last_step_with_behaviour_var('_tries_' . $index); if (!$step->has_behaviour_var('_tries_' . $index)) { return new qbehaviour_adaptivemultipart_mark_details(question_state::$todo); } $weights = $this->question->get_parts_and_weights(); $state = question_state::graded_state_for_fraction($step->get_behaviour_var('_rawfraction_' . $index)); $details = new qbehaviour_adaptivemultipart_mark_details($state); $details->maxmark = $weights[$index] * $this->qa->get_max_mark(); $details->actualmark = $step->get_behaviour_var('_fraction_' . $index) * $details->maxmark; $details->rawmark = $step->get_behaviour_var('_rawfraction_' . $index) * $details->maxmark; $details->currentpenalty = $step->get_behaviour_var('_curpenalty_' . $index) * $details->maxmark; $details->totalpenalty = $step->get_behaviour_var('_penalty_' . $index) * $details->maxmark; $details->improvable = !$state->is_correct(); return $details; }
public function grade_response(array $response) { $fraction = 0; foreach ($this->prts as $index => $prt) { $results = $this->get_prt_result($index, $response, true); $fraction += $results->fraction; } return array($fraction, question_state::graded_state_for_fraction($fraction)); }
public function grade_response(array $response) { if ($this->rightanswer == true && $response['answer'] == true) { $fraction = 1; } else { if ($this->rightanswer == false && $response['answer'] == false) { $fraction = 1; } else { $fraction = 0; } } return array($fraction, question_state::graded_state_for_fraction($fraction)); }
/** * Output the content of the subquestion. * * @param question_attempt $qa * @param question_display_options $options * @param int $index * @param question_graded_automatically $subq * @return string */ public function subquestion(question_attempt $qa, question_display_options $options, $index, question_graded_automatically $subq) { if (!$subq instanceof qtype_multichoice_multi_question) { throw new coding_exception('Expecting subquestion of type qtype_multichoice_multi_question'); } $fieldprefix = 'sub' . $index . '_'; $fieldname = $fieldprefix . 'choice'; // Extract the responses that related to this question + strip off the prefix. $fieldprefixlen = strlen($fieldprefix); $response = []; foreach ($qa->get_last_qt_data() as $name => $val) { if (substr($name, 0, $fieldprefixlen) == $fieldprefix) { $name = substr($name, $fieldprefixlen); $response[$name] = $val; } } $basename = $qa->get_qt_field_name($fieldname); $inputattributes = array( 'type' => 'checkbox', 'value' => 1, ); if ($options->readonly) { $inputattributes['disabled'] = 'disabled'; } $result = $this->all_choices_wrapper_start(); // Calculate the total score (as we need to know if choices should be marked as 'correct' or 'partial'). $fraction = 0; foreach ($subq->get_order($qa) as $value => $ansid) { $ans = $subq->answers[$ansid]; if ($subq->is_choice_selected($response, $value)) { $fraction += $ans->fraction; } } // Display 'correct' answers as correct, if we are at 100%, otherwise mark them as 'partial'. $answerfraction = ($fraction > 0.999) ? 1.0 : 0.5; foreach ($subq->get_order($qa) as $value => $ansid) { $ans = $subq->answers[$ansid]; $name = $basename.$value; $inputattributes['name'] = $name; $inputattributes['id'] = $name; $isselected = $subq->is_choice_selected($response, $value); if ($isselected) { $inputattributes['checked'] = 'checked'; } else { unset($inputattributes['checked']); } $class = 'r' . ($value % 2); if ($options->correctness && $isselected) { $thisfrac = ($ans->fraction > 0) ? $answerfraction : 0; $feedbackimg = $this->feedback_image($thisfrac); $class .= ' ' . $this->feedback_class($thisfrac); } else { $feedbackimg = ''; } $result .= $this->choice_wrapper_start($class); $result .= html_writer::empty_tag('input', $inputattributes); $result .= html_writer::tag('label', $subq->format_text($ans->answer, $ans->answerformat, $qa, 'question', 'answer', $ansid), array('for' => $inputattributes['id'])); $result .= $feedbackimg; if ($options->feedback && $isselected && trim($ans->feedback)) { $result .= html_writer::tag('div', $subq->format_text($ans->feedback, $ans->feedbackformat, $qa, 'question', 'answerfeedback', $ansid), array('class' => 'specificfeedback')); } $result .= $this->choice_wrapper_end(); } $result .= $this->all_choices_wrapper_end(); $feedback = array(); if ($options->feedback && $options->marks >= question_display_options::MARK_AND_MAX && $subq->maxmark > 0) { $a = new stdClass(); $a->mark = format_float($fraction * $subq->maxmark, $options->markdp); $a->max = format_float($subq->maxmark, $options->markdp); $feedback[] = html_writer::tag('div', get_string('markoutofmax', 'question', $a)); } if ($options->rightanswer) { $correct = []; foreach ($subq->answers as $ans) { if (question_state::graded_state_for_fraction($ans->fraction) != question_state::$gradedwrong) { $correct[] = $subq->format_text($ans->answer, $ans->answerformat, $qa, 'question', 'answer', $ans->id); } } $correct = '<ul><li>'.implode('</li><li>', $correct).'</li></ul>'; $feedback[] = get_string('correctansweris', 'qtype_multichoice', $correct); } $result .= html_writer::nonempty_tag('div', implode('<br />', $feedback), array('class' => 'outcome')); return $result; }
public function subquestion(question_attempt $qa, question_display_options $options, $index, question_graded_automatically $subq) { $fieldprefix = 'sub' . $index . '_'; $fieldname = $fieldprefix . 'answer'; $response = $qa->get_last_qt_var($fieldname); $inputattributes = array( 'type' => 'radio', 'name' => $qa->get_qt_field_name($fieldname), ); if ($options->readonly) { $inputattributes['disabled'] = 'disabled'; } $result = $this->all_choices_wrapper_start(); $fraction = null; foreach ($subq->get_order($qa) as $value => $ansid) { $ans = $subq->answers[$ansid]; $inputattributes['value'] = $value; $inputattributes['id'] = $inputattributes['name'] . $value; $isselected = $subq->is_choice_selected($response, $value); if ($isselected) { $inputattributes['checked'] = 'checked'; $fraction = $ans->fraction; } else { unset($inputattributes['checked']); } $class = 'r' . ($value % 2); if ($options->correctness && $isselected) { $feedbackimg = $this->feedback_image($ans->fraction); $class .= ' ' . $this->feedback_class($ans->fraction); } else { $feedbackimg = ''; } $result .= $this->choice_wrapper_start($class); $result .= html_writer::empty_tag('input', $inputattributes); $result .= html_writer::tag('label', $subq->format_text($ans->answer, $ans->answerformat, $qa, 'question', 'answer', $ansid), array('for' => $inputattributes['id'])); $result .= $feedbackimg; if ($options->feedback && $isselected && trim($ans->feedback)) { $result .= html_writer::tag('div', $subq->format_text($ans->feedback, $ans->feedbackformat, $qa, 'question', 'answerfeedback', $ansid), array('class' => 'specificfeedback')); } $result .= $this->choice_wrapper_end(); } $result .= $this->all_choices_wrapper_end(); $feedback = array(); if ($options->feedback && $options->marks >= question_display_options::MARK_AND_MAX && $subq->maxmark > 0) { $a = new stdClass(); $a->mark = format_float($fraction * $subq->maxmark, $options->markdp); $a->max = format_float($subq->maxmark, $options->markdp); $feedback[] = html_writer::tag('div', get_string('markoutofmax', 'question', $a)); } if ($options->rightanswer) { foreach ($subq->answers as $ans) { if (question_state::graded_state_for_fraction($ans->fraction) == question_state::$gradedright) { $feedback[] = get_string('correctansweris', 'qtype_multichoice', $subq->format_text($ans->answer, $ans->answerformat, $qa, 'question', 'answer', $ansid)); break; } } } $result .= html_writer::nonempty_tag('div', implode('<br />', $feedback), array('class' => 'outcome')); return $result; }
public function correct_response(question_attempt $qa) { $question = $qa->get_question(); foreach ($question->answers as $ansid => $ans) { if (question_state::graded_state_for_fraction($ans->fraction) == question_state::$gradedright) { return get_string('correctansweris', 'qtype_multichoice', $question->format_text($ans->answer, $ans->answerformat, $qa, 'question', 'answer', $ansid)); } } return ''; }
public function correct_response(question_attempt $qa) { $question = $qa->get_question(); // Put all correct answers (100% grade) into $right. $right = array(); foreach ($question->answers as $ansid => $ans) { if (question_state::graded_state_for_fraction($ans->fraction) == question_state::$gradedright) { $right[] = $question->make_html_inline($question->format_text($ans->answer, $ans->answerformat, $qa, 'question', 'answer', $ansid)); } } return $this->correct_choices($right); }
public function correct_response(question_attempt $qa) { $right = array(); $result = ""; $question = $qa->get_question(); if ($question->shownumcorrect) { foreach ($question->get_order($qa) as $ans_number => $ans_id) { $answer = $question->answers[$ans_id]; if (question_state::graded_state_for_fraction($answer->fraction) == question_state::$gradedright) { foreach (explode(",", $answer->answer) as $k => $v) { array_push($right, '<i roi-shape-id="' . $v . '" class="glyphicon glyphicon-map-marker roi-shape-info"></i> ' . '[' . $v . "]"); } } } $result = get_string(count($right) == 1 ? 'single_correctansweris' : 'single_correctanswerare', 'qtype_omerointeractive') . implode(", ", $right); } return $result; }