Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tidy up questiontype.php and question.php #834537 #5

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 71 additions & 44 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 correct responses and the total numbe 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 {
// Retrieve the number of right responses and the total number of responses.
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,36 @@ 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.

public function compute_final_grade(array $responses, int $totaltries): int|float {
$grade = 0;
foreach ($responses as $response) {
if ($totaltries === 1) {
foreach ($responses as $key => $response) {
[$fraction, $state] = $this->grade_response($response);
$grade += $fraction;
}
return $grade;
}
$reversedresponses = array_reverse($responses, true);
for ($tr = $totaltries; $tr >= 1; $tr--) {
$response = $reversedresponses[$tr];
[$fraction, $state] = $this->grade_response($response);
$grade += $fraction;

// Apply penalties.
[$numright, $numtotal] = $this->retrieve_numright_numtotal($response);
$penalty = ($numtotal - $numright) * ($this->penalty / $numtotal);
$grade += $fraction - $penalty;
}
return $grade;
$finalgrade = $grade / $totaltries;
return $finalgrade;
}

/**
* 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"
Loading
Loading