Skip to content

Commit

Permalink
Tidy up questiontype.php and question.php #834537
Browse files Browse the repository at this point in the history
  • Loading branch information
mkassaei committed Nov 19, 2024
1 parent 82310b6 commit 18af616
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 77 deletions.
119 changes: 74 additions & 45 deletions question.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class qtype_drawlines_question extends question_graded_automatically {
public function get_expected_data() {
$expecteddata = [];
foreach ($this->lines as $line) {
$expecteddata[$this->choice($line->number - 1)] = PARAM_RAW;
$expecteddata[$this->field($line->number - 1)] = PARAM_RAW;
}
return $expecteddata;
}
Expand All @@ -75,8 +75,8 @@ public function is_complete_response(array $response): bool {
return false;
}
foreach ($this->lines as $key => $line) {
if (isset($response[$this->choice($key)]) &&
!line::are_response_coordinates_valid($response[$this->choice($key)], $line->type)) {
if (isset($response[$this->field($key)]) &&
!line::are_response_coordinates_valid($response[$this->field($key)], $line->type)) {
return false;
}
}
Expand All @@ -87,7 +87,7 @@ public function is_complete_response(array $response): bool {
public function get_correct_response() {
$response = [];
foreach ($this->lines as $key => $line) {
$response[$this->choice($key)] = line::get_coordinates($line->zonestart) . ' '
$response[$this->field($key)] = line::get_coordinates($line->zonestart) . ' '
. line::get_coordinates($line->zoneend);
}
return $response;
Expand All @@ -98,14 +98,14 @@ public function summarise_response(array $response): ?string {
$responsewords = [];
$answers = [];
foreach ($this->lines as $key => $line) {
if (array_key_exists($this->choice($key), $response) && $response[$this->choice($key)] != '') {
$coordinates = explode(' ', $response[$this->choice($key)]);
if (array_key_exists($this->field($key), $response) && $response[$this->field($key)] != '') {
$coordinates = explode(' ', $response[$this->field($key)]);
if ($line->type == 'lineinfinite' && count($coordinates) == 4) {
$coordinates = explode(' ', $response[$this->choice($key)]);
$coordinates = explode(' ', $response[$this->field($key)]);
$answers[] = 'Line ' . $line->number . ': ' . $coordinates[1] . ' ' . $coordinates[2];
continue;
}
$answers[] = 'Line ' . $line->number . ': ' . $response[$this->choice($key)];
$answers[] = 'Line ' . $line->number . ': ' . $response[$this->field($key)];
}
}
if (count($answers) > 0) {
Expand All @@ -117,7 +117,7 @@ public function summarise_response(array $response): ?string {
#[\Override]
public function is_gradable_response(array $response) {
foreach ($this->lines as $key => $line) {
if (array_key_exists($this->choice($key), $response)) {
if (array_key_exists($this->field($key), $response)) {
return true;
}
}
Expand All @@ -127,40 +127,28 @@ public function is_gradable_response(array $response) {
#[\Override]
public function is_same_response(array $prevresponse, array $newresponse) {
foreach ($this->lines as $key => $line) {
$fieldname = $this->choice($key);
$fieldname = $this->field($key);
if (!question_utils::arrays_same_at_key_missing_is_blank($prevresponse, $newresponse, $fieldname)) {
return false;
}
}
return true;
}

#[\Override]
public function grade_response(array $response): array {
// Retrieve the number of right responses and the total number of responses.
if ($this->grademethod == 'partial') {
[$numright, $total] = $this->get_num_parts_right_grade_partialt($response);
} else {
[$numright, $total] = $this->get_num_parts_right_grade_allornone($response);
}
$fraction = $numright / $total;
return [$fraction, question_state::graded_state_for_fraction($fraction)];
}

/**
* Get the number of correct choices selected in the response, for 'Give partial credit' grade method.
*
* @param array $response The response list.
* @return array The array of number of correct lines (start, end or both points of lines).
*/
public function get_num_parts_right_grade_partialt(array $response): array {
public function get_num_parts_right_grade_partial(array $response): array {
if (!$response) {
return [0, 0];
}
$numpartright = 0;
foreach ($this->lines as $key => $line) {
if (array_key_exists($this->choice($key), $response) && $response[$this->choice($key)] !== '') {
$coords = explode(' ', $response[$this->choice($key)]);
if (array_key_exists($this->field($key), $response) && $response[$this->field($key)] !== '') {
$coords = explode(' ', $response[$this->field($key)]);
if ($line->type == 'lineinfinite') {
if (count($coords) == 2) {
// Response with 2 coordinates (x1,y1 x2,y2).
Expand All @@ -185,12 +173,15 @@ public function get_num_parts_right_grade_partialt(array $response): array {
}
}
} else {
$numpartrightstart = 0;
$numpartrightend = 0;
if (line::is_dragitem_in_the_right_place($coords[0], $line->zonestart)) {
$numpartright++;
$numpartrightstart++;
}
if (line::is_dragitem_in_the_right_place($coords[1], $line->zoneend)) {
$numpartright++;
$numpartrightend++;
}
$numpartright += $numpartrightstart + $numpartrightend;
}
}
}
Expand All @@ -210,25 +201,25 @@ public function get_num_parts_right_grade_allornone(array $response): array {
}
$numright = 0;
foreach ($this->lines as $key => $line) {
if (array_key_exists($this->choice($key), $response) && $response[$this->choice($key)] !== '') {
$coords = explode(' ', $response[$this->choice($key)]);
if (array_key_exists($this->field($key), $response) && $response[$this->field($key)] !== '') {
$coords = explode(' ', $response[$this->field($key)]);
if ($line->type == 'lineinfinite') {
if (count($coords) == 2) {
// Response with 2 coordinates (x1,y1 x2,y2 x3,y3 x4,y4).
$isstartrightplace = line::is_item_positioned_correctly_on_axis(
$coords[0], $line->zonestart, $line->zoneend, 'start'
$coords[0], $line->zonestart, $line->zoneend, 'start'
);
$isendrightplace = line::is_item_positioned_correctly_on_axis(
$coords[1], $line->zonestart, $line->zoneend, 'end'
$coords[1], $line->zonestart, $line->zoneend, 'end'
);
} else {
// Response has 4 coordinates(x1,y1 x2,y2 x3,y3 x4,y4).
// Here we need to consider x2,y2 x3,y3 for calculation.
$isstartrightplace = line::is_item_positioned_correctly_on_axis(
$coords[1], $line->zonestart, $line->zoneend, 'start'
$coords[1], $line->zonestart, $line->zoneend, 'start'
);
$isendrightplace = line::is_item_positioned_correctly_on_axis(
$coords[2], $line->zonestart, $line->zoneend, 'end'
$coords[2], $line->zonestart, $line->zoneend, 'end'
);
}
if ($isstartrightplace && $isendrightplace) {
Expand Down Expand Up @@ -274,15 +265,15 @@ public function get_validation_error(array $response): string {
public function classify_response(array $response) {
$classifiedresponse = [];
foreach ($this->lines as $key => $line) {
if (array_key_exists($this->choice($key), $response) && $response[$this->choice($key)] !== '') {
if (array_key_exists($this->field($key), $response) && $response[$this->field($key)] !== '') {
if ($this->grademethod == 'partial') {
$fraction = 0.5;
} else {
$fraction = 1;
}
$classifiedresponse[$key] = new question_classified_response(
$line->number,
'Line ' . $line->number . ': ' . $response[$this->choice($key)],
'Line ' . $line->number . ': ' . $response[$this->field($key)],
$fraction);
} else {
$classifiedresponse[$key] = question_classified_response::no_response();
Expand All @@ -291,6 +282,30 @@ public function classify_response(array $response) {
return $classifiedresponse;
}


#[\Override]
public function grade_response(array $response): array {
// Retrieve the number of right responses and the total number of responses.
[$numright, $numtotal] = $this->retrieve_numright_numtotal($response);
$fraction = $numright / $numtotal;
return [$fraction, question_state::graded_state_for_fraction($fraction)];
}

/**
* Return number of right responses and the total number of answers.
*
* @param array $response The respnse array
* @return array|int[] The array containing number of correct responses and the total.
*/
public function retrieve_numright_numtotal(array $response): array {
if ($this->grademethod == 'partial') {
[$numright, $numtotal] = $this->get_num_parts_right_grade_partial($response);
} else {
[$numright, $numtotal] = $this->get_num_parts_right_grade_allornone($response);
}
return [$numright, $numtotal];
}

/**
* Work out a final grade for this attempt, taking into account
* all the tries the student made and return the grade value.
Expand All @@ -304,24 +319,38 @@ public function classify_response(array $response) {
* @return float the fraction that should be awarded for this
* sequence of response.
*/
public function compute_final_grade(array $responses, int $totaltries): float {
// TODO: To incorporate the question penalty for interactive with multiple tries behaviour.

$grade = 0;
foreach ($responses as $response) {
public function compute_final_grade(array $responses, int $totaltries): int|float {
$penalties = 0;
foreach ($responses as $attempt => $response) {
[$fraction, $state] = $this->grade_response($response);
$grade += $fraction;
if ($state->is_graded() === true) {
if ($totaltries === 1) {
return round($fraction, 7);
}
if ($state->get_feedback_class() === 'correct') {
$grade = max(0, $fraction - $penalties);
return round($grade, 7);
}
[$numright, $numtotal] = $this->retrieve_numright_numtotal($response);
if ($state->get_feedback_class() === 'incorrect') {
$penalties += $this->penalty;
} else if ($state->get_feedback_class() === 'partiallycorrect') {
$partpenaly = ($numtotal - $numright) * $this->penalty / $totaltries;
$penalties += min($this->penalty, round($partpenaly, 7));
}
}
}
return $grade;
$grade = max(0, $fraction - $penalties);
return round($grade, 7);
}

/**
* Get a choice identifier
* Get a choice index identifier
*
* @param int $choice stem number
* @param int $choice
* @return string the question-type variable name.
*/
public function choice($choice) {
public function field($choice): string {
return 'c' . $choice;
}
}
6 changes: 0 additions & 6 deletions questiontype.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,6 @@ public function save_hints($fromform, $withparts = false) {
}
}

#[\Override]
protected function make_question_instance($questiondata) {
question_bank::load_question_definition_classes($this->name());
return new qtype_drawlines_question;
}

#[\Override]
protected function initialise_question_instance(question_definition $question, $questiondata): void {
parent::initialise_question_instance($question, $questiondata);
Expand Down
2 changes: 1 addition & 1 deletion renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ protected function hidden_field_for_qt_var(question_attempt $qa, $varname, $valu
* @return mixed
*/
protected function hidden_field_choice(question_attempt $qa, $choicenumber, $value = null, $class = null) {
$varname = 'c'. $choicenumber;
$varname = $qa->get_question()->field($choicenumber);
$classes = ['choices', 'choice'. $choicenumber];
[, $html] = $this->hidden_field_for_qt_var($qa, $varname, $value, $classes);
return $html;
Expand Down
4 changes: 2 additions & 2 deletions tests/behat/preview.feature
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ Feature: Preview a DrawLines question

@javascript
Scenario: Preview a question using the keyboard
When I am on the "Drawlines to preview" "core_question > preview" page logged in as teacher
Given I am on the "Drawlines to preview" "core_question > preview" page logged in as teacher
And I type "up" "360" times on line "1" "line" in the drawlines question
And I type "left" "40" times on line "1" "line" in the drawlines question
And I type "down" "190" times on line "1" "endcircle" in the drawlines question
And I type "left" "200" times on line "1" "endcircle" in the drawlines question
And I press "Submit and finish"
When I press "Submit and finish"
Then the state of "Draw 2 lines on the map" question is shown as "Partially correct"
And I should see "Mark 0.50 out of 1.00"
2 changes: 1 addition & 1 deletion tests/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public function make_drawlines_question_mkmap_twolines(): qtype_drawlines_questi
11, $question->id, 1, line::TYPE_LINE_SEGMENT,
'Start1', 'Mid1', 'End1', '10,10;12', '300,10;12'),
1 => new line(
11, $question->id, 2, line::TYPE_LINE_SEGMENT,
12, $question->id, 2, line::TYPE_LINE_SEGMENT,
'Start2', '', 'End2', '10,200;12', '300,200;12'),
];

Expand Down
Loading

0 comments on commit 18af616

Please sign in to comment.