[Merged][BugFix] Bug #5405 - made a new function that grades a lesson for a specific user's attempt. This is then used for grading lessons at the end of a lesson, for ongoing score feature and for updating the grade for essay question grading.

This new grading algorithm now enforces the lesson setting Max attempts when custom scoring is turned Off

Changed the reporting of minquestions setting to match the help file.  Now it is question based instead of attempt based.

Changed the reporting of ongoing score to use the new grade function.
This commit is contained in:
mark-nielsen 2006-05-19 01:05:13 +00:00
parent c23ff4d654
commit 88427c077b
4 changed files with 184 additions and 248 deletions

View File

@ -179,10 +179,10 @@ $string['notitle'] = 'No title';
$string['numberofcorrectanswers'] = 'Number of correct answers: $a';
$string['numberofcorrectmatches'] = 'Number of correct matches: $a';
$string['numberofpagestoshow'] = 'Number of pages (cards) to show';
$string['numberofpagesviewed'] = 'Number of pages viewed: $a';
$string['numberofpagesviewed'] = 'Number of questions answered: $a';
$string['ongoing'] = 'Display ongoing score';
$string['ongoingcustom'] = 'You have earned $a->score point(s) out of $a->currenthigh point(s) thus far.';
$string['ongoingnormal'] = 'You have answered $a->correct question(s) correctly out of $a->viewed question(s).';
$string['ongoingnormal'] = 'You have answered $a->correct correctly out of $a->viewed attempts.';
$string['or'] = 'OR';
$string['ordered'] = 'Ordered';
$string['other'] = 'Other';
@ -284,7 +284,7 @@ $string['youranswer'] = 'Your answer';
$string['yourcurrentgradeis'] = 'Your current grade is $a';
$string['yourgradeisnow'] = 'Your grade for the lesson has been changed to $a';
$string['yourresponse'] = 'Your response';
$string['youshouldview'] = 'You should view at least: $a';
$string['youshouldview'] = 'You should answer at least: $a';

View File

@ -704,17 +704,9 @@
}
}
// this calculates the ongoing score
// This calculates and prints the ongoing score message
if ($lesson->ongoing) {
if (isteacher($course->id)) {
echo "<div align=\"center\">".get_string("teacherongoingwarning", "lesson")."</div><br>";
} else {
$ntries = count_records("lesson_grades", "lessonid", $lesson->id, "userid", $USER->id);
if (isset($USER->modattempts[$lesson->id])) {
$ntries--;
}
lesson_calculate_ongoing_score($lesson, $USER->id, $ntries);
}
lesson_print_ongoing_score($lesson);
}
// display response (if there is one - there should be!)

View File

@ -1204,123 +1204,155 @@ function lesson_print_tree($pageid, $lesson, $cmid) {
/**
* Calculates a user's grade for a lesson.
*
* This is used for the ongoing score feature. It will calculate the user's
* score based on how many points they have earned thus far in the lesson out
* of the maximum that they could have earned. Example: user answers 4 questions out
* of 20. Of the 4, the user earned 5 points out of a possible 12. So, their current
* score would be 5 out of 12 and not 5 out of the total for the whole lesson.
* This function is also used by essay grading. It is used to recalculate a students grade
* after a teacher assigns a grade for an essay.
*
* @param object $lesson The lesson that the user is taking.
* @param int $userid Id of the user.
* @param int $retries The attempt number.
* @param boolean $return A flag to return the grade or print it out.
* @return float May return the grade.
* @todo Break out the grading section of this code to use for grading lessons (also have grading code in view.php)
* @param int $userid Id of the user (optinal, default current user).
* @return object { nquestions => number of questions answered
attempts => number of question attempts
total => max points possible
earned => points earned by student
grade => calculated percentage grade
nmanual => number of manually graded questions
manualpoints => point value for manually graded questions }
*/
function lesson_calculate_ongoing_score($lesson, $userid, $retries, $return=false) {
if (!$lesson->custom) {
$ncorrect = 0;
$temp = array();
if ($pagesanswered = get_records_select("lesson_attempts", "lessonid = $lesson->id AND
userid = $userid AND retry = $retries order by timeseen")) {
function lesson_grade($lesson, $ntries, $userid = 0) {
global $USER;
foreach ($pagesanswered as $pageanswered) {
if (!array_key_exists($pageanswered->pageid, $temp)) {
$temp[$pageanswered->pageid] = array($pageanswered->correct, 1);
} else {
if ($temp[$pageanswered->pageid][1] < $lesson->maxattempts) {
$n = $temp[$pageanswered->pageid][1] + 1;
$temp[$pageanswered->pageid] = array($pageanswered->correct, $n);
}
}
}
foreach ($temp as $value => $key) {
if ($key[0] == 1) {
$ncorrect += 1;
}
}
if (empty($userid)) {
$userid = $USER->id;
}
// Zero out everything
$ncorrect = 0;
$nviewed = 0;
$score = 0;
$nmanual = 0;
$manualpoints = 0;
$thegrade = 0;
$nquestions = 0;
$total = 0;
$earned = 0;
if ($useranswers = get_records_select("lesson_attempts", "lessonid = $lesson->id AND
userid = $userid AND retry = $ntries", "timeseen")) {
// group each try with its page
$attemptset = array();
foreach ($useranswers as $useranswer) {
$attemptset[$useranswer->pageid][] = $useranswer;
}
$nviewed = count($temp); // this counts number of Questions the user viewed
if ($nviewed != 0) {
$thegrade = round(100 * $ncorrect / $nviewed, 5);
} else {
$thegrade = 0;
}
if ($return) {
return $thegrade;
} else {
$output = new stdClass;
$output->correct = $ncorrect;
$output->viewed = $nviewed;
print_simple_box(get_string("ongoingnormal", "lesson", $output), "center");
}
} else {
$score = 0;
$essayquestions = 0;
$essayquestionpoints = 0;
$bestscore = 0;
$thegrade = 0;
if ($useranswers = get_records_select("lesson_attempts", "lessonid = $lesson->id AND
userid = $userid AND retry = $retries", "timeseen")) {
// group each try with its page
foreach ($useranswers as $useranswer) {
$attemptset[$useranswer->pageid][] = $useranswer;
}
$pageids = array_keys($attemptset);
$pageids = implode(",", $pageids);
// get only the pages and their answers that the user answered
$answeredpages = get_records_select("lesson_pages", "lessonid = $lesson->id AND id IN($pageids)");
$pageanswers = get_records_select("lesson_answers", "lessonid = $lesson->id AND pageid IN($pageids)");
foreach ($attemptset as $attempts) {
if(count($attempts) > $lesson->maxattempts) { // if there are more tries than the max that is allowed, grab the last "legal" attempt
$attempt = $attempts[$lesson->maxattempts - 1];
} else {
// else, user attempted the question less than the max, so grab the last one
$attempt = end($attempts);
}
// if essay question, handle it, otherwise add to score
if ($answeredpages[$attempt->pageid]->qtype == LESSON_ESSAY) {
$essayinfo = unserialize($attempt->useranswer);
$score += $essayinfo->score;
$essayquestions++;
$essayquestionpoints += $pageanswers[$attempt->answerid]->score;
} else {
$score += $pageanswers[$attempt->answerid]->score;
}
}
$bestscores = array();
// find the highest possible score per page
foreach ($pageanswers as $pageanswer) {
if(isset($bestscores[$pageanswer->pageid])) {
if ($bestscores[$pageanswer->pageid] < $pageanswer->score) {
$bestscores[$pageanswer->pageid] = $pageanswer->score;
}
} else {
$bestscores[$pageanswer->pageid] = $pageanswer->score;
}
}
$bestscore = array_sum($bestscores);
$thegrade = round(100 * $score / $bestscore, 5);
}
if ($return) {
return $thegrade;
// Drop all attempts that go beyond max attempts for the lesson
foreach ($attemptset as $key => $set) {
$attemptset[$key] = array_slice($set, 0, $lesson->maxattempts);
}
$pageids = implode(",", array_keys($attemptset));
// get only the pages and their answers that the user answered
$pages = get_records_select("lesson_pages", "lessonid = $lesson->id AND id IN($pageids)");
$answers = get_records_select("lesson_answers", "lessonid = $lesson->id AND pageid IN($pageids)");
// Number of pages answered
$nquestions = count($pages);
foreach ($attemptset as $attempts) {
if ($lesson->custom) {
$attempt = end($attempts);
// If essay question, handle it, otherwise add to score
if ($pages[$attempt->pageid]->qtype == LESSON_ESSAY) {
$essayinfo = unserialize($attempt->useranswer);
$earned += $essayinfo->score;
$nmanual++;
$manualpoints += $answers[$attempt->answerid]->score;
} else {
$earned += $answers[$attempt->answerid]->score;
}
} else {
foreach ($attempts as $attempt) {
$earned += $attempt->correct;
}
$attempt = end($attempts); // doesn't matter which one
// If essay question, increase numbers
if ($pages[$attempt->pageid]->qtype == LESSON_ESSAY) {
$nmanual++;
$manualpoints++;
}
}
// Number of times answered
$nviewed += count($attempts);
}
if ($lesson->custom) {
$bestscores = array();
// Find the highest possible score per page to get our total
foreach ($answers as $answer) {
if(isset($bestscores[$answer->pageid]) and $bestscores[$answer->pageid] < $answer->score) {
$bestscores[$answer->pageid] = $answer->score;
} else {
$bestscores[$answer->pageid] = $answer->score;
}
}
$total = array_sum($bestscores);
} else {
// not taking into account essay questions... may want to?
$ongoingoutput = new stdClass;
$ongoingoutput->score = $score;
$ongoingoutput->currenthigh = $bestscore;
print_simple_box(get_string("ongoingcustom", "lesson", $ongoingoutput), "center");
// Check to make sure the student has answered the minimum questions
if ($lesson->minquestions and $nquestions < $lesson->minquestions) {
// Nope, increase number viewed by the amount of unanswered questions
$total = $nviewed + ($lesson->minquestions - $nquestions);
} else {
$total = $nviewed;
}
}
}
if ($total) { // not zero
$thegrade = round(100 * $earned / $total, 5);
}
// Build the grade information object
$gradeinfo = new stdClass;
$gradeinfo->nquestions = $nquestions;
$gradeinfo->attempts = $nviewed;
$gradeinfo->total = $total;
$gradeinfo->earned = $earned;
$gradeinfo->grade = $thegrade;
$gradeinfo->nmanual = $nmanual;
$gradeinfo->manualpoints = $manualpoints;
return $gradeinfo;
}
/**
* Prints the on going message to the user.
*
* With custom grading On, displays points
* earned out of total points possible thus far.
* With custom grading Off, displays number of correct
* answers out of total attempted.
*
* @param object $lesson The lesson that the user is taking.
* @return void
**/
function lesson_print_ongoing_score($lesson) {
global $USER;
if (isteacher($lesson->course)) {
echo "<p align=\"center\">".get_string('teacherongoingwarning', 'lesson').'</p>';
} else {
$ntries = count_records("lesson_grades", "lessonid", $lesson->id, "userid", $USER->id);
if (isset($USER->modattempts[$lesson->id])) {
$ntries--;
}
$gradeinfo = lesson_grade($lesson, $ntries);
$a = new stdClass;
if ($lesson->custom) {
$a->score = $gradeinfo->earned;
$a->currenthigh = $gradeinfo->total;
print_simple_box(get_string("ongoingcustom", "lesson", $a), "center");
} else {
$a->correct = $gradeinfo->earned;
$a->viewed = $gradeinfo->attempts;
print_simple_box(get_string("ongoingnormal", "lesson", $a), "center");
}
}
}

View File

@ -630,45 +630,28 @@
}
}
/// this calculates the ongoing score
if ($lesson->ongoing && !empty($pageid)) {
if (isteacher($course->id)) {
echo "<p align=\"center\">".get_string('teacherongoingwarning', 'lesson').'</p>';
} else {
$ntries = count_records("lesson_grades", "lessonid", $lesson->id, "userid", $USER->id);
if (isset($USER->modattempts[$lesson->id])) {
$ntries--;
}
lesson_calculate_ongoing_score($lesson, $USER->id, $ntries);
}
/// This calculates and prints the ongoing score
if ($lesson->ongoing and !empty($pageid)) {
lesson_print_ongoing_score($lesson);
}
if ($page->qtype == LESSON_BRANCHTABLE) {
if ($lesson->minquestions and isstudent($course->id)) {
// tell student how many questions they have seen, how many are required and their grade
$ntries = count_records("lesson_grades", "lessonid", $lesson->id, "userid", $USER->id);
$nviewed = count_records("lesson_attempts", "lessonid", $lesson->id, "userid",
$USER->id, "retry", $ntries);
if ($nviewed) {
echo "<p align=\"center\">".get_string("numberofpagesviewed", "lesson", $nviewed).
$gradeinfo = lesson_grade($lesson, $ntries);
if ($gradeinfo->attempts) {
echo "<p align=\"center\">".get_string("numberofpagesviewed", "lesson", $gradeinfo->nquestions).
"; (".get_string("youshouldview", "lesson", $lesson->minquestions).")<br />";
// count the number of distinct correct pages
if ($correctpages = get_records_select("lesson_attempts", "lessonid = $lesson->id
AND userid = $USER->id AND retry = $ntries AND correct = 1")) {
foreach ($correctpages as $correctpage) {
$temp[$correctpage->pageid] = 1;
}
$ncorrect = count($temp);
} else {
$nccorrect = 0;
if ($gradeinfo->nquestions < $lesson->minquestions) {
$gradeinfo->nquestions = $lesson->minquestions;
}
if ($nviewed < $lesson->minquestions) {
$nviewed = $lesson->minquestions;
}
echo get_string("numberofcorrectanswers", "lesson", $ncorrect)."<br />\n";
$thegrade = intval(100 * $ncorrect / $nviewed);
echo get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned)."<br />\n";
echo get_string("yourcurrentgradeis", "lesson",
number_format($thegrade * $lesson->grade / 100, 1)).
number_format($gradeinfo->grade * $lesson->grade / 100, 1)).
" (".get_string("outof", "lesson", $lesson->grade).")</p>\n";
}
}
@ -1019,110 +1002,40 @@
$ntries--; // need to look at the old attempts :)
}
if (isstudent($course->id)) {
if ($nviewed = count_records("lesson_attempts", "lessonid", $lesson->id, "userid",
$USER->id, "retry", $ntries)) {
$gradeinfo = lesson_grade($lesson, $ntries);
if ($gradeinfo->attempts) {
if (!$lesson->custom) {
$ncorrect = 0;
$temp = array();
// count the number of distinct correct pages
if ($correctpages = get_records_select("lesson_attempts", "lessonid = $lesson->id AND
userid = $USER->id AND retry = $ntries AND correct = 1")) {
foreach ($correctpages as $correctpage) {
$temp[$correctpage->pageid] = 1;
}
$ncorrect = count($temp);
}
echo "<p align=\"center\">".get_string("numberofpagesviewed", "lesson", $nviewed).
echo "<p align=\"center\">".get_string("numberofpagesviewed", "lesson", $gradeinfo->nquestions).
"</p>\n";
if ($lesson->minquestions) {
if ($nviewed < $lesson->minquestions) {
if ($gradeinfo->nquestions < $lesson->minquestions) {
// print a warning and set nviewed to minquestions
echo "<p align=\"center\">".get_string("youshouldview", "lesson",
$lesson->minquestions)." ".get_string("pages", "lesson")."</p>\n";
$nviewed = $lesson->minquestions;
$lesson->minquestions)."</p>\n";
}
}
echo "<p align=\"center\">".get_string("numberofcorrectanswers", "lesson", $ncorrect).
echo "<p align=\"center\">".get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned).
"</p>\n";
$thegrade = round(100 * $ncorrect / $nviewed, 5);
echo "<p align=\"center\">".get_string("gradeis", "lesson",
number_format($thegrade * $lesson->grade / 100, 1)).
" (".get_string("outof", "lesson", $lesson->grade).")</p>\n";
} else {
$score = 0;
$essayquestions = 0;
$essayquestionpoints = 0;
if ($useranswers = get_records_select("lesson_attempts", "lessonid = $lesson->id AND
userid = $USER->id AND retry = $ntries", "timeseen")) {
// group each try with its page
foreach ($useranswers as $useranswer) {
$attemptset[$useranswer->pageid][] = $useranswer;
}
$pageids = array_keys($attemptset);
$pageids = implode(",", $pageids);
// get only the pages and their answers that the user answered
$answeredpages = get_records_select("lesson_pages", "lessonid = $lesson->id AND id IN($pageids)");
$pageanswers = get_records_select("lesson_answers", "lessonid = $lesson->id AND pageid IN($pageids)");
foreach ($attemptset as $attempts) {
if(count($attempts) > $lesson->maxattempts) { // if there are more tries than the max that is allowed, grab the last "legal" attempt
$attempt = $attempts[$lesson->maxattempts - 1];
} else {
// else, user attempted the question less than the max, so grab the last one
$attempt = end($attempts);
}
// if essay question, handle it, otherwise add to score
if ($answeredpages[$attempt->pageid]->qtype == LESSON_ESSAY) {
$essayinfo = unserialize($attempt->useranswer);
$score += $essayinfo->score;
$essayquestions++;
$essayquestionpoints += $pageanswers[$attempt->answerid]->score;
} else {
if (array_key_exists($attempt->answerid, $pageanswers)) {
$score += $pageanswers[$attempt->answerid]->score;
}
}
}
$bestscores = array();
// find the highest possible score per page
foreach ($pageanswers as $pageanswer) {
if(isset($bestscores[$pageanswer->pageid])) {
if ($bestscores[$pageanswer->pageid] < $pageanswer->score) {
$bestscores[$pageanswer->pageid] = $pageanswer->score;
}
} else {
$bestscores[$pageanswer->pageid] = $pageanswer->score;
}
}
$bestscore = array_sum($bestscores);
}
$thegrade = round(100 * $score / $bestscore, 5);
$a = new stdClass;
if ($essayquestions > 0) {
$a->score = $score;
$a->tempmaxgrade = $bestscore - $essayquestionpoints;
$a->essayquestions = $essayquestions;
$a->grade = $bestscore;
echo "<div align=\"center\">".get_string("displayscorewithessays", "lesson", $a)."</div>";
} else {
$a->score = $score;
$a->grade = $bestscore;
echo "<div align=\"center\">".get_string("displayscorewithoutessays", "lesson", $a)."</div>";
}
echo "<p align=\"center\">".get_string("gradeis", "lesson",
number_format($thegrade * $lesson->grade / 100, 1)).
" (".get_string("outof", "lesson", $lesson->grade).")</p>\n";
}
$a = new stdClass;
$a->score = $gradeinfo->earned;
$a->grade = $gradeinfo->total;
if ($gradeinfo->nmanual) {
$a->tempmaxgrade = $gradeinfo->total - $gradeinfo->manualpoints;
$a->essayquestions = $gradeinfo->nmanual;
echo "<div align=\"center\">".get_string("displayscorewithessays", "lesson", $a)."</div>";
} else {
echo "<div align=\"center\">".get_string("displayscorewithoutessays", "lesson", $a)."</div>";
}
echo "<p align=\"center\">".get_string("gradeis", "lesson",
number_format($gradeinfo->grade * $lesson->grade / 100, 1)).
" (".get_string("outof", "lesson", $lesson->grade).")</p>\n";
$grade->lessonid = $lesson->id;
$grade->userid = $USER->id;
$grade->grade = $thegrade;
$grade->grade = $gradeinfo->grade;
$grade->completed = time();
if (!$lesson->practice) {
if (isset($USER->modattempts[$lesson->id])) { // if reviewing, make sure update old grade record
@ -1821,10 +1734,9 @@
$grade = current($grades);
// I modded this function a bit so it would work here... :) ;) :P
$updategrade->grade = lesson_calculate_ongoing_score($lesson, $essay->userid, $essay->retry, true);
$gradeinfo = lesson_grade($lesson, $essay->retry, $essay->userid);
$updategrade->id = $grade->id;
$updategrade->grade = $gradeinfo->grade;
if(update_record("lesson_grades", $updategrade)) {
redirect("view.php?id=$cm->id&amp;action=essayview", get_string("updatesuccess", "lesson"));
} else {