WeBWorK Problems

Customizing List answer checkers

Customizing List answer checkers

by Michael Gage -
Number of replies: 4
I have customized a point answer checker as follows:

$answer_point = Compute("($x0, $y0)");
NAMED_ANS('answerBox'=>$answer_point->with(tolType=>"absolute",tolerance=>.05)->cmp->
 withPostFilter(AnswerHints(
 sub {
 my ($correct,$student,$ans) = @_;
 return Vector($correct-$student)->norm<.2 ;
 } => ["You're close. You need to position the dot more precisely.", replaceMessage=>1]
)));

So that if the student's answer is somewhat close they get an encouraging

message to reposition the point to make the answer correct.


Is there a simple way to check a list of 3 points entered in any order?

My first experiments seem to indicate that the AnswerHints subroutine above
won't work as is because it is handed the entire list, not a single point at a time.

Any hints on another way to approach this are appreciated.

The problem arises in checking points positioned by students on a graph. The single point version is at

http://hosted2.webwork.rochester.edu/webwork2/applet_dev/PointAndGraph_AppletDemos/3/

and the multipoint version (without any helpful hints) is at

http://hosted2.webwork.rochester.edu/webwork2/applet_dev/PointAndGraph_AppletDemos/4/


In reply to Michael Gage

Re: Customizing List answer checkers

by Davide Cervone -
It looks like you are working on an interesting problem. I'm hoping that eventually dragging the points on the graph will cause the coordinates for the point in the answer blanks for the inflection point, max, and min to change automatically. Any chance of that?

As for getting the hint for a list, here's one way to do it. I'm assuming you don't care about saying which point is the one that is close (since the mapping from points on the screen to positions in the list is not obvious), and just want a single message when at least one point is close but not equal.

Here's the sample code:


    ANS($anser_list->cmp
      (checker => sub {
        my ($correct,$student,$ans) = @_;
        if ($correct == $student) {$student->{isClose} = 0; return 1}
        $student->{isClose} = 1 if Vector($correct-$student)->norm < .3*$tolerance;
        return 0;
      })->withPostFilter(AnswerHints(sub {
        my ($correct,$student,$ans) = @_;
        $student = List($student) unless $student->class eq "List";
        foreach $point ($student->value) {return 1 if $point->{isClose}}
        return 0;
      } => ["You're close.  You need to position the dots more precisely"]
  )));

For a List() object, the checker is used on the individual entries in the list, and may be called several times as it looks through the list to see which entries match. Our checker keeps track of whether an individual entry is close to one in the correct list (but not equal to it); each student answer is marked as to whether it is close or not. (When an entry is found to be equal, the List checker stops comparing that student answer, so we don't have to worry about isClose being set again later).

When the post-filter runs, we scan through the student answers to see if any are close, and issue the hint in that case. The second line of the answer hint subroutine turns a single point into a list in the event that the student only types one point. This is not strictly necessary in your case, since the student is not actually typing the answer (it comes from the applet), but since others may use this as a template for their own problems, I include it here.

Hope that does what you need.

Davide

In reply to Davide Cervone

Re: Customizing List answer checkers

by Michael Gage -
Davide,

Thanks for the example and the explanation of how the list answer checker works. I'll get to work on implementing it in the example.

It looks like you are working on an interesting problem. I'm hoping that eventually dragging the points on the graph will cause the coordinates for the point in the answer blanks for the inflection point, max, and min to change automatically. Any chance of that?

In the example the written answer blanks are checked completely separately from the dots on the graph --- one could leave off the answer blanks entirely and simply position the dots --- the dots' coordinates are placed in a hidden answer blank as a list and checked directly using the list object.

I added the answer blanks in the spirit of requiring the student to answer the question in more than one way -- visual and numerical.

One could easily have the flash applet itself display the coordinates of each dot. It currently displays the coordinates of the cursor in real time. In principle its possible to create a javaScript listener and have the flash applet send out events, but that seems unnecessarily complicated for this example. Geogebra applets have this event/listener facility but I've found it still fairly fragile when you are trying to deploy it across many browsers and platforms.

Incidentally the flash applet is an extension of the graph and point flash applet presented by Doug Ensley in a WeBWorK video conference a few months ago.

-- Mike
In reply to Michael Gage

Re: Customizing List answer checkers

by Davide Cervone -
Thanks for the example and the explanation of how the list answer checker works.
BTW, there is also a list_checker that can be used to replace the entire list checker (rather than the one that checks the individual pieces), but that is rarely needed. I mention it for the record in case others look here later.
In the example the written answer blanks are checked completely separately from the dots on the graph
Yes, I saw that. One thing that bothers me is that the coordinates include the colors, so the student sees that funny extra coordinate in the answer results. It would be possible to post-filter that answer checker to replace the student answer and preview (and correct answer) with something more meaningful to the student. Even "The points on the graph" or something like that might be better.
I added the answer blanks in the spirit of requiring the student to answer the question in more than one way -- visual and numerical.
I suppose it depends on what you are trying to accomplish in the problem. It seems to me that if you are trying to see if they can identify the right points on the graph, the coordinates are not the crucial thing, and whether they can read the coordinates off the lower left corner and copy them into the answer blank seems superfluous to me. I would be annoyed at that if I were a student. If dragging the point around updated the answer showing in each of those three places, I would think that that made the connection between the point and the coordinate clear. (That would also mean there was no need for the hidden answer checker, and you would not get an extra list of points in the results table that may seem redundant to the students.)

Davide
In reply to Davide Cervone

Re: Customizing List answer checkers

by Davide Cervone -
It occurs to me this may not actually do what you want. Note that it will say you are close if any ONE point is close. You may want to say that only if ALL the points are either correct or close. To do that, you can set $student->{isEqual} = 1 in addition to clearing $student->{isClose} in the checker and modify the answer hint routine to return 0 if neither is set and 1 otherwise.

Alternatively, since the answer hint routine is only called if the answer is not correct, you could just set $student->{isClose} = 1 when it is actually equal (rather than using a separate field isEqual) and that will simplify both the checker and the testing in the answer hint routine.

Untested code:


    ANS($anser_list->cmp
      (checker => sub {
        my ($correct,$student,$ans) = @_;
        $student->{isClose} = 1 if Vector($correct-$student)->norm < .3*$tolerance;
        return $correct == $student;
      })->withPostFilter(AnswerHints(sub {
        my ($correct,$student,$ans) = @_;
        $student = List($student) unless $student->class eq "List";
        foreach $point ($student->value) {return 0 unless $point->{isClose}}
        return 1;
      } => ["You're close.  You need to position at least one dot more precisely"]
    )));

Davide