# Sample of giving partial credit for a "checkbox_multiple_choice" question # using answerHints.pl. It will not give partial credit when no box is marked. # Code by Nathan Wallach taniwallach@gmail.com, tani@technion.ac.il # K.Andew Parker kparker@citytech.cuny.edu # suggested including the "total % possible" in the debug report. DOCUMENT(); loadMacros( "PGstandard.pl", "PGchoicemacros.pl", "answerHints.pl", ); TEXT(beginproblem()); $mc1 = new_checkbox_multiple_choice(); # The correct answer strings: # In this sample problem, there are 3 correct answers.$mc1->qa ("", "Correct 1 $$b^2 + a^2$$", "Correct 2 $$(a+b)^2 - 2ab$$", "Correct 3 $$(a-b)^2 + 2ab$$", ); # Incorrect answers to show: # In this sample problem, there are 5 incorrect answers. $mc1->extra( "Incorrect 1 $$(a+b)^2$$", "Incorrect 2 $$(a-b)^2$$", "Incorrect 3 $$(a+b)^2 + 2ab$$", "Incorrect 4 $$(a-b)^2 - 2ab$$", "Incorrect 5 $$a + b$$", ); # =============================================================== BEGIN_TEXT Let $$a,b \in \mathbb{R}$$. Select all expressions below which are equivalent to $$a^2 + b^2$$.$PAR \{ $mc1->print_a() \}$PAR Partial credit is given, except when no boxes are marked. END_TEXT ANS( checkbox_cmp( $mc1->correct_ans() )->withPostFilter(sub { my$ans = shift; # ====================================================== # Settings - fix by hand according to the problem # number of total "items" (checkboxes) my $numItems = 8; # Credit for correct answers which the student marked:$pointsForCorrectAndMarked = (1.0 / $numItems); # Credit for incorrect answers which the student did not mark:$pointsForIncorrectAndUnmarked = (1.0 / $numItems); # The two types of credit need to be equal, but should be set so a # fully correct answer earns a total of 1.0 "points" (100%). # Sample alternate values for this sample problem$pointsForCorrectAndMarked = 0.3; $pointsForIncorrectAndUnmarked = 0.02; # ====================================================== # I could not get this approach to give partial credit when nothing is marked # As such, you may want to consider also not giving partial credit # when all answers are marked. # This can be done by responding appropriately for the answer string for all # answers marked, as in the sample below (8 answers). # # So we are also not giving partial credit if everything is marked # if ($ans->{student_ans} eq "ABCDEFGH" ) { # return $ans; # } my @stud_chars = split //,$ans->{student_ans}; my @corr_chars = split //, $ans->{correct_ans}; my @only_corr = (); my @only_stud = (); my @both = (); while ( scalar(@stud_chars) > 0 && scalar(@corr_chars) > 0 ) {$first_s = ord( $stud_chars[0] );$first_c = ord( $corr_chars[0] ); if ($first_s == $first_c ) { push( @both, shift( @stud_chars ) ); shift( @corr_chars ); } elsif ($first_s < $first_c ) { push( @only_stud, shift( @stud_chars ) ); } else { push( @only_corr, shift( @corr_chars ) ); } } @only_stud = ( @only_stud, @stud_chars); @only_corr = ( @only_corr, @corr_chars); @stud_chars = split //,$ans->{student_ans}; @corr_chars = split //, $ans->{correct_ans};$ans->{score} = $pointsForCorrectAndMarked * scalar( @both ); # These were marked and are correct # so earn credit by$pointsForCorrectAndMarked my $unmarked_and_incorrect =$numItems - scalar( @both ) - scalar( @only_stud ) - scalar( @only_corr ); $ans->{score} +=$pointsForIncorrectAndUnmarked * $unmarked_and_incorrect; # These were NOT marked and should not be # so earn credit by$pointsForIncorrectAndUnmarked my $debugOn = 0; # change to 1 to get the debug message if ($debugOn ) { # Save the counts before adding "*none*" if needed. my @counters = ( (0 + @stud_chars), (0 + @corr_chars), (0 + @both), (0 + @only_stud), (0 + @only_corr) ); unless( @only_stud ) { push( @only_stud, "*none*" ); } unless( @only_corr ) { push( @only_corr, "*none*" ); } unless( @both ) { push( @both, "*none*" ); } unless( @stud_chars ) { push( @stud_chars, "*none*" ); } unless( @corr_chars ) { push( @corr_chars, "*none*" ); } $pt1a = sprintf("%2.1f", 100 *$pointsForCorrectAndMarked); $pt2a = sprintf("%2.1f", 100 *$pointsForIncorrectAndUnmarked); $pt1b = sprintf("%2.1f", 100 *$pointsForCorrectAndMarked * $counters[2]);$pt2b = sprintf("%2.1f", 100 * $pointsForIncorrectAndUnmarked *$unmarked_and_incorrect); $score2 = sprintf("%2.1f", 100 *$ans->{score} ); $tmpM = round( 1000 * ($pointsForCorrectAndMarked * scalar(@corr_chars) + $pointsForIncorrectAndUnmarked * ($numItems - scalar(@corr_chars) ) ) ); $maxscore = sprintf("%2.1f", 0.1 *$tmpM ); # For debugging $ans->{ans_message} = "student marked: " . join(",",@stud_chars) . " ($counters[0] answers)" . "${BR}correct answers: " . join(",",@corr_chars) . " ($counters[1] answers)" . "${HR}both: " . join(",",@both) . " ($counters[2] answers, $pt1a points each,$pt1b earned)" . "${BR}# unmarked and incorrect:$unmarked_and_incorrect answers, $pt2a points each,$pt2b earned" . "${BR}total earned:${score2}%" . "${HR}only student: " . join(",",@only_stud) . " ($counters[3] answers, incorrect - no credit)" . "${BR}only correct: " . join(",",@only_corr) . " ($counters[4] answers, incorrect - no credit)" . "${HR}total % possible:${maxscore}%"; } return \$ans; }) ); ENDDOCUMENT();