WeBWorK Problems

Score Math Object

Score Math Object

by Alex Jordan -
Number of replies: 4
I am cleaning up some work that ultimately is meant to streamline using GGB in a problem. One tool for this is a "Score" math object. It's supposed to work like this. With an interactive applet, you might design it to figure out for itself whether the student gets credit. So there is a hidden answer blank, and as the user plays with the applet, javascript is inserting something in this hidden answer blank. Maybe "1" if the user is "correct". Maybe "0" if not. Maybe "0.5" if the applet deems the user deserves partial credit.

So the user hits Submit button, and if there is a "1" in the answer blank, they get credit. A "0.5", half credit. A "0", no credit. Some number not in [0, 1], an appropriate error message that something went wrong. Some other string not recognized by the parser as a Real, and an appropriate error message.

I will be using this for GGB, but it seems like a thing that other applets could make use of. So I am separating this into its own parserScore.pl file. If this is loaded, then no matter what context is active, I want Score(1) to be understood to take a Score object.

What I have right now is here:

I would like to ask knowedgeable people to look at this (it's pretty small) and critique it. I know it is not exactly right yet. For example, I found that if I load Context("Fraction") and have $score = Score(1) as an answer, and I enter "1/2" in the answer blank, it leads to a messy error. [What I would want is for the "1/2" to be promoted to Real("1/2"), but the error suggests it is still Fraction("1/2").]

Note: it may seem that making a MathObject for this is overkill. Maybe something simpler would do. But if I can assume that this thing is a MathObject, it goes a long way to help with the other things I am doing with GGB.

In reply to Alex Jordan

Re: Score Math Object

by Michael Gage -
I'm at the NA Perl conference next week, but I'll look at it as soon as I can. I don't think it is too small a project to have a MathObject for it.

Eventually we might not need a separate file to include the object. It's possible that an overhaul of the current AppletObjects.pl and Applet.pm files could include it or that it's included in files that part of the standard include suite. I've felt that
AppletObjects.pl and Applet.pm two files are past due for an overhaul.
In particular I believe the support for Java and Flash objects can be removed -- I don't see any utility in continuing to support them.

You might look at them and see if you think that GGB completely supersedes the support for Geogebra objects. Would GGB support Desmos objects as well?

-- Mike
In reply to Michael Gage

Re: Score Math Object

by Alex Jordan -
GGB is just my lazy shorthand for GeoGebra. I'm building a parserGeogebra.pl (which relies on parserScore.pl) for a different approach than that used by AppletObjects.pl, that will make use of MathObjects.

It may be GeoGebra-specific, or in the end I may see how it could generalize.

I don't want to get off-thread with respect to the Score Math Object, but with parserGeoGebra.pl, you can do things like:

$displayGGB = GeoGebra()->with(params that define the applet);
$webworkGGB = GeoGebra("2x+3y=7")->with(params that define the applet);
$geogebraGGB = GeoGebra(Score(1),"2x+3y=7")->with(params that define the applet);

And then in the body, using PGML syntax:

Here is an applet to play with:


Here is an applet you have to manipulate just right, then hit submit to get credit. Answer checking is done by WeBWorK, and you get credit if GeoGebra is returning something that is equivalent to "2x+3y=7" in the ImplicitPlane context.


Here is another applet you have to manipulate just right, then hit submit to get credit. Answer checking is gone by GeoGebra, and you get credit if GeoGebra thinks you deserve it and sends "1" back to WeBWorK.


In reply to Alex Jordan

Re: Score Math Object

by Davide Cervone -
I have a couple of suggestions for you. First, you don't have to use the current context, but can have your object always use a special context that is only for your score objects. That way, you don't run into the issues with fractions or other contexts that might not properly evaluate your score (e.g., LimitedComplex when exponential notation is required).

This is accomplished by making a private copy of the Numeric context and then using that when you create your Score object (see the code below). Here, I also remove all the variables and the comma operator, so you can basically only enter numeric values. I'm allowing expressions (including function calls and constants like pi), but you could remove those as well, if you like. You might want to remove the strings, but I haven't done that.

I add the default checker subroutine into the context's cmpDefaults hash as an alternative to overriding cmp_defaults. It also returns the underlying Perl real rather than the MathObject, since the scoring code doesn't know about MathObjects.

Finally, I fixed the check for whether the score is between 0 and 1 (you had an "or" when you want an "and").

See if that is more to your liking.


sub _parserScore_init {
  main::PG_restricted_eval('sub Score {value::Score->new(@_)}');

package value::Score;
our @ISA = ('Value::Real');

#  A context for score opbjects
my $context = Parser::Context->getCopy('Numeric');
$context->{name} = "Score";
$context->{value}{Real} = 'value::Score';       # real numbers create Score objects
$context->variables->clear();                   # no formulas in this context
$context->operators->undefine(',');             # lists not allowed, either

$context->{cmpDefaults}{Score} = {
  checker => sub {
    my ($correct, $student, $ansHash) = @_;
    my $score = $student->value;
    Value::Error('A score must be a real number between 0 and 1')
      unless $score >= 0 && $score <= 1;
    return $score;

sub new {
  my $self = shift;
  my $score = $self->SUPER::new($context, @_);
  Value::Error("A score must be a real number between 0 and 1")
      unless Value::isReal($score) && $score->value >= 0 && $score->value <= 1;
  $score->{isReal} = $score->{isValue} = $score->{isScore} = 1;
  return $score;

#  Override the class name to get better error messages
sub cmp_class {"a Score Value"}


In reply to Davide Cervone

Re: Score Math Object

by Alex Jordan -
Thanks Davide,

It's working great. Stay tuned for more questions about the related parserGeoGebra.pl :)