WeBWorK Problems

Problems using student input

Problems using student input

by Steven Fiedler -
Number of replies: 8

It would be nice to be able to capture the values that students enter in a problem for subsequent calculation within the same problem.

I have found some inroads toward accomplishing this. 

  • Student answers can now be captured and used in subsequent questions using the new externalData.pl functionality (e.g., the linked examples).  
  • Previously, I found that the inputs_ref variable could capture student answers in gateway quizzes.
  • The Custom Answer Checker wiki page describes how variables can be transferred into an answer checker subroutine.
  • Some developers weighed in on a similar matter a few years ago in their responses to the linked question.
  • Scaffold problems used to permit capturing student data for use in subsequent sections, but this appears to be depreciated in version 2.19.

This issue pertains to an inability to extract values out of an answer checker subroutine.  Attached is a MWE demonstrates a simple use case and the limitation.  I would appreciate any guidance for accomplishing this task.

In reply to Steven Fiedler

Re: Problems using student input

by Glenn Rice -

You can already get an answer to any previous question in the problem in numerous ways.

  • The external data approach was never needed for this.
  • Using the inputs_ref is a very sloppy approach for this, but would also work for homework assignments.  You are probably just using the wrong answer name which is different in homework assignments.  That is part of why this approach is sloppy, and I don't recommend using it.
  • The scaffold problem approach should have never worked, and it was always a hack to use such an approach.
The key is to access the answer hash from the previous answer.  It has everything you could ever want, including the score that answer received.  Here is a minimal example:

DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl', 'PGcourse.pl');

$ans1 = Real(0)->cmp(
    checker => sub {
        my ($correct, $student, $ansHash) = @_;
        return 1;
    }
);

$ans2 = Real(1)->cmp(
    checker => sub {
        my ($correct, $student, $ansHash) = @_;
        return defined $ans1->rh_ans->{student_value} && $ans1->rh_ans->{student_value} + 1 == $student ? 1 : 0;
    }
);

BEGIN_PGML
Enter a number: [_]{$ans1}{5}

Add [`1`] to your previous answer: [_]{$ans2}{5}
END_PGML

ENDDOCUMENT();
The example shows  using the "student_value" which is the MathObject parsed student answer.  But you can also use the "student_ans" which is the evaluated string answer, or the "original_student_ans" which is the same as what you would get from the inputs ref.  Note that $ans1->rh_ans is literally the $ansHash inside the first answer checker, except that by the time the second answer evaluator is called it will have all data filled in from evaluating the first answer.
In reply to Glenn Rice

Re: Problems using student input

by Steven Fiedler -
Thank you Glenn. This was very helpful.
In reply to Steven Fiedler

Re: Problems using student input

by Glenn Rice -
By the way here is the correct way to obtain an answer from the $inputs_ref that will work reliably regardless of where the problem is used (in a homework assignment or gateway quiz or any of the other places that a problem can be used).


DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl', 'PGcourse.pl');

$ans1 = Real(0)->cmp(
    checker => sub {
        my ($correct, $student, $ansHash) = @_;
        return 1;
    }
);

$ans1name = NEW_ANS_NAME();

$ans2 = Real(1)->cmp(
    checker => sub {
        my ($correct, $student, $ansHash) = @_;
        return defined $ans1->rh_ans->{student_value} && $ans1->rh_ans->{student_value} + 1 == $student ? 1 : 0;
    }
);

BEGIN_PGML
Enter a number: [_]{$ans1}{5}{$ans1name}

[@ if ($inputs_ref->{$ans1name}) { 'You entered [$inputs_ref->{$ans1name}].' } @]**

Add [`1`] to your previous answer: [_]{$ans2}{5}
END_PGML

ENDDOCUMENT();
There are quite a few places where it is suggested to use AnSwEr0001 or Q0001_AnSwEr0001 and such for answer names as well as using named answers with a hard coded made up answer name.  Never do any of that.  Anyone that suggests such a thing is completely incorrect in offering such advice.  Use an answer name given by NEW_ANS_NAME.  That will reliably give you an answer name that will work anywhere a problem is rendered.  Unfortunately, this will only work reliably for WeBWorK 2.19 or newer.  There was no completely reliable way to do this prior to 2.19.

By the way, it should also be pointed out that the previous example that I gave would certainly be better to do using a MultiAnswer as Davide suggested in the linked question you referenced before.  At least if that was the question that you wanted to present.
In reply to Glenn Rice

Re: Problems using student input

by Steven Fiedler -
Thanks Glenn. A couple years ago, I spent quite some time trying to get inputs_ref to work.

Regarding the MWE - my use case is a problem that collects multiple entries of student input and subsequently has multiple entries where students input the result of their calculations (with their own data). It's now fairly trivial to stack the "collection answers" like in the below fragment.
$ans1 = Real(0)->cmp(checker => sub {return 1;} );
$ans2 = Real(0)->cmp(checker => sub {return 1;} );
$ans3 = Real(0)->cmp(checker => sub {return 1;} );
$ans4 = Real(0)->cmp(checker => sub {return 1;} );

I suspect that use of MultiAnswer in this case might obfuscate the code more than it could provide an advantage.
In reply to Steven Fiedler

Re: Problems using student input

by Glenn Rice -

I haven't seen what you are really trying to do, but I highly doubt that using a multi answer would obfuscate the code. In fact I think the approaches discussed here do obfuscate the code in most cases compared to using a multi answer. The cases are quite rare that these approaches are better, and the multi answer approach almost always gives an advantage.

In reply to Glenn Rice

Re: Problems using student input

by Steven Fiedler -
Below is one of the problems I'm working on tonight. It appears to be relatively complete except for sig figs, which I'll put in later. I also appreciate having the option of displaying the value of the student entries, although I did not choose to do that for this problem. If there is a way to make this problem more tidy with MultiAnswer, I would greatly appreciate the guidance.


In reply to Steven Fiedler

Re: Problems using student input

by Glenn Rice -

This is exactly the sort of problem that parserMultiAnswer.pl is designed for, and is certainly more clear using a MultiAnswer object.

Here is the code:

DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl', 'parserMultiAnswer.pl', 'PGcourse.pl');

$ma = MultiAnswer(0, 0, 0, 0, 0)->with(
    checker => sub {
        my ($correct, $student, $self, $ansHash) = @_;
        my $mass        = $student->[0];
        my $h2o_cyl     = $student->[1];
        my $h2o_bar_cyl = $student->[2];
        my $vol         = $student->[3];

        my $den     = $mass / $vol;
        my $bar_vol = $h2o_bar_cyl - $h2o_cyl;

        return (
            1, 1, 1,
            $bar_vol == $vol      ? 1 : 0,
            $den == $student->[4] ? 1 : 0
        );
    }
);

BEGIN_PGML
*_Determining the Density of a Solid Metal Bar_*

A. Mass of your metal bar: [_]{$ma}{10} g.

B. Initial volume of water in the graduated cylinder: [_]{$ma}{10} mL.

C. Volume of water and metal bar in the graduated cylinder: [_]{$ma}{10} mL.

D. Calculate the volume of your metal bar: [_]{$ma}{10} mL.

E. Calculate the density of your metal bar: [_]{$ma}{10} g/mL.
END_PGML

ENDDOCUMENT();
In reply to Glenn Rice

Re: Problems using student input

by Steven Fiedler -
By combining the two approaches, I suspect that the contents of $ma can also be accessed (and displayed).
Thanks again Glenn. Down the line, I hope that this thread will help someone as much as it helped me.