From c3bd5e18fa760723eabc6207ed57a2d8a90faea1 Mon Sep 17 00:00:00 2001 From: Jaimos Skriletz Date: Sat, 5 Feb 2022 00:01:23 -0700 Subject: [PATCH] Rework how reduced scoring is computed and stored. This is paired with removing reduced scoring from PG. Instead webwork should take the raw score from PG and apply any reduced scoring adjustments to it. The new method compute_reduced_score in ProblemUtils determines if a set is in the reduced scoring period, applies any reduced scoring adjustments to the portion of the score earned during the reduced scoring period, then returns the reduced score. To be be able to store the raw score in the data base without adding a new column, the column sub_status is used to store the raw score instead of only the portion of the score earned before the reduced scoring period. In order to be able to invert the reduced scoring computation to get the portion of the score earned before and after the reduced scoring period, the reducedScoringValue is used. This means that if a user changes the value of reducedScoringValue, problems that are open and have a reduced scoring adjustment will no longer be able to correctly compute the portion earned before and after the reduced scoring date. --- lib/WeBWorK/AchievementEvaluator.pm | 1 - lib/WeBWorK/ContentGenerator/GatewayQuiz.pm | 15 +++++-- .../ProblemUtil/ProblemUtil.pm | 41 +++++++++++++++++-- lib/WeBWorK/DB/Record/UserProblem.pm | 4 +- lib/WeBWorK/PG/Local.pm | 3 +- lib/WeBWorK/PG/Remote.pm | 3 +- 6 files changed, 52 insertions(+), 15 deletions(-) diff --git a/lib/WeBWorK/AchievementEvaluator.pm b/lib/WeBWorK/AchievementEvaluator.pm index b0aa6c20b9..ac2884066b 100644 --- a/lib/WeBWorK/AchievementEvaluator.pm +++ b/lib/WeBWorK/AchievementEvaluator.pm @@ -105,7 +105,6 @@ sub checkForAchievements { # $pg->{result} reflects the current submission, $pg->{state} holds the best result # close the unlimited achievement points loophole by only using the current result! $problem->status($pg->{result}->{score}); - $problem->sub_status($pg->{state}->{sub_recorded_score}); $problem->attempted(1); $problem->num_correct($pg->{state}->{num_of_correct_ans}); $problem->num_incorrect($pg->{state}->{num_of_incorrect_ans}); diff --git a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm index b9d6f0c92b..d15fc6e14a 100644 --- a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm +++ b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm @@ -1456,11 +1456,17 @@ sub body { # next, store the state in the database if that makes sense if ($submitAnswers && $will{recordAnswers}) { - $problems[$i]->status(wwRound(2,$pg_results[$i]->{state}->{recorded_score})); + # Reduced scoring adjustments + my $new_score = WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil::compute_reduced_score( + $self, $pureProblem, $set, $pg_results[$i]->{state}->{recorded_score}); + + $problems[$i]->status(wwRound(2,$new_score)); + $problems[$i]->sub_status($pg_results[$i]->{state}->{recorded_score}); $problems[$i]->attempted(1); $problems[$i]->num_correct($pg_results[$i]->{state}->{num_of_correct_ans}); $problems[$i]->num_incorrect($pg_results[$i]->{state}->{num_of_incorrect_ans}); - $pureProblem->status(wwRound(2,$pg_results[$i]->{state}->{recorded_score})); + $pureProblem->status(wwRound(2,$new_score)); + $pureProblem->sub_status($pg_results[$i]->{state}->{recorded_score}); $pureProblem->attempted(1); $pureProblem->num_correct($pg_results[$i]->{state}->{num_of_correct_ans}); $pureProblem->num_incorrect($pg_results[$i]->{state}->{num_of_incorrect_ans}); @@ -1746,8 +1752,9 @@ sub body { my $pScore = 0; my $numParts = 0; if (ref($pg)) { # then we have a pg object - ### - $pScore = $pg->{state}->{recorded_score}; + # Reduced scoring adjustments + $pScore = WeBWorK::ContentGenerator::ProblemUtil::ProblemUtil::compute_reduced_score( + $self, $problems[$i], $set, $pg->{state}->{recorded_score}); $probStatus[$i] = $pScore; $numParts = 1; ### diff --git a/lib/WeBWorK/ContentGenerator/ProblemUtil/ProblemUtil.pm b/lib/WeBWorK/ContentGenerator/ProblemUtil/ProblemUtil.pm index bc8dbbf37f..f1c701dec0 100644 --- a/lib/WeBWorK/ContentGenerator/ProblemUtil/ProblemUtil.pm +++ b/lib/WeBWorK/ContentGenerator/ProblemUtil/ProblemUtil.pm @@ -134,13 +134,16 @@ sub process_and_log_answer{ # store state in DB if it makes sense if ($will{recordAnswers}) { - $problem->status($pg->{state}->{recorded_score}); - $problem->sub_status($pg->{state}->{sub_recorded_score}); + # Reduced scoring adjustments + my $new_score = compute_reduced_score($self, $problem, $set, $pg->{state}->{recorded_score}); + + $problem->status($new_score); + $problem->sub_status($pg->{state}->{recorded_score}); $problem->attempted(1); $problem->num_correct($pg->{state}->{num_of_correct_ans}); $problem->num_incorrect($pg->{state}->{num_of_incorrect_ans}); - $pureProblem->status($pg->{state}->{recorded_score}); - $pureProblem->sub_status($pg->{state}->{sub_recorded_score}); + $pureProblem->status($new_score); + $pureProblem->sub_status($pg->{state}->{recorded_score}); $pureProblem->attempted(1); $pureProblem->num_correct($pg->{state}->{num_of_correct_ans}); $pureProblem->num_incorrect($pg->{state}->{num_of_incorrect_ans}); @@ -675,4 +678,34 @@ Comment: $comment return ""; } +# Determines if a set is in the reduced scoring period and applies +# the reduced scoring adjustment to the portion of the score earned +# during the reduced scoring period. +sub compute_reduced_score { + my ($self, $problem, $set, $new_status) = @_; + + my $r = $self->r; + my $reducedScoringEnabled = $r->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; + my $reducedScoringValue = $r->{ce}->{pg}{ansEvalDefaults}{reducedScoringValue}; + + # If no adjustments need to be applied, return the full score. + if (! $reducedScoringEnabled + || ! $set->enable_reduced_scoring + || ! $set->reduced_scoring_date + || $set->reduced_scoring_date == $set->due_date + || time < $set->reduced_scoring_date + || $reducedScoringValue == 1 + ) { + return $new_status; + } + + # Invert the reduced scoring computation to get the portion of the + # grade earned before the reduced scoring date, then return the + # adjusted score by applying the reduced scoring adjustment to the + # portion done after the reduced scoring date. + my $pre_reduced_score = $problem->sub_status - ($problem->sub_status + - $problem->status) / (1 - $reducedScoringValue); + return $pre_reduced_score + $reducedScoringValue * ($new_status - $pre_reduced_score); +} + 1; diff --git a/lib/WeBWorK/DB/Record/UserProblem.pm b/lib/WeBWorK/DB/Record/UserProblem.pm index f3c0812b94..0e848a0d72 100644 --- a/lib/WeBWorK/DB/Record/UserProblem.pm +++ b/lib/WeBWorK/DB/Record/UserProblem.pm @@ -43,14 +43,14 @@ BEGIN { # periodic re-randomization number of attempts for the current seed prCount => {type => "INT"}, problem_seed => { type=>"INT" }, - status => { type=>"FLOAT" }, + status => { type=>"FLOAT" }, # The adjusted problem score attempted => { type=>"INT" }, last_answer => { type=>"TEXT" }, num_correct => { type=>"INT" }, num_incorrect => { type=>"INT" }, att_to_open_children => { type=>"INT" }, counts_parent_grade => { type=>"INT" }, - sub_status => { type=>"FLOAT" }, # A subsidiary status used to implement the reduced scoring period + sub_status => { type=>"FLOAT" }, # The raw problem score before any adjustments # a field for flags which need to be set flags => { type=>"TEXT" }, ); diff --git a/lib/WeBWorK/PG/Local.pm b/lib/WeBWorK/PG/Local.pm index cf1071eaff..e105968b04 100644 --- a/lib/WeBWorK/PG/Local.pm +++ b/lib/WeBWorK/PG/Local.pm @@ -375,8 +375,7 @@ EOF #warn "PG: retrieving the problem state and giving it to the translator\n"; $translator->rh_problem_state({ - recorded_score => $problem->status, - sub_recorded_score => $problem->sub_status, + recorded_score => $problem->sub_status, # using sub_status since it is the raw score. num_of_correct_ans => $problem->num_correct, num_of_incorrect_ans => $problem->num_incorrect, }); diff --git a/lib/WeBWorK/PG/Remote.pm b/lib/WeBWorK/PG/Remote.pm index 573c396eed..0920a671b8 100644 --- a/lib/WeBWorK/PG/Remote.pm +++ b/lib/WeBWorK/PG/Remote.pm @@ -99,8 +99,7 @@ EOF extra_packages_to_load => [ @extra_packages_to_load ], envir => $envir, problem_state => { - recorded_score => $problem->status, - sub_recorded_score => $problem->sub_status, + recorded_score => $problem->sub_status, # Using sub_status since it is the raw score. num_of_correct_ans => $problem->num_correct, num_of_incorrect_ans => $problem->num_incorrect, },