WeBWorK Problems

Variables in strings

Variables in strings

by Olivia Henders -
Number of replies: 3
I'm trying to fix up a question that generates random binary numbers and gets the student to convert them to hexadecimal. Because the hexadecimal values may have A-F in them, I'm using the following for my answer checker, where each $answer MathObject contains a string defining that answer:
Context()->strings->add($answer1=>{}, $answer2=>{}, $answer3=>{});
ANS(String($answer1)->cmp());
ANS(String($answer2)->cmp());
ANS(String($answer3)->cmp());

However, this still causes problems. Namely, any letters that appear after the most significant digit get interpreted as variables. This causes the correct answer to be marked wrong, as, if the answer is "17A", WeBWorK complains that "Variable 'A' is not defined in this Context". Interestingly, though, the answer "A65" works fine, as do others that have the "variable" going first. How do I go about restricting WeBWorK to exclusively process all these values as strings?


In reply to Olivia Henders

Re: Variables in strings

by Michael Gage -
There is another approach.

It's not hard to convert a hex string to an integer.

hex() does this -- in pure pearl. Google "perl hex" for more details.

These two snippets of code are in compoundProblem.pl -- an obsolete macro file that has been replaced by scaffold.pl -- and in randomizeProblem.pl.

#
# Hex encoding is shifted by 10 to obfuscate it further.
# (shouldn't be a problem since the status will be made of
# printable characters, so they are all above ASCII 32)
#
sub toHex {main::spf(ord(shift)-10,"%X")}
sub fromHex {main::spf(hex(shift)+10,"%c")}

spf -- is the PG equivalent of sprintf from perl (or fortran)

I think you could use a custom answer checker to check the student's answer.
As usual the hardest part would be giving reasonable error messages if the syntax
In reply to Michael Gage

Re: Variables in strings

by Olivia Henders -
Thank you for the response!

As it happens, generating the hex values wasn't the issue: it was just the way that the values were being interpreted by the answer checker. Thankfully, there was a much easier solution than creating a custom answer checker. All that's actually necessary is to use str_cmp instead of the regular answer checker. You don't even need to add the strings to the Context then! :-D
In reply to Olivia Henders

Re: Variables in strings

by Davide Cervone -
As you have found out, this is really not the way to go about this. Even had you succeeded in defining your values as strings in the context, no other hex numbers would be there, so any other hex value would produce error messages.

The technical reason why your string "17A" didn't work while "A65" did is because the various object types each have a priority, and it turns out that numbers are before strings (by default, though that can be changed), so the "17" in "17A" matched as a number, leaving the "A" as the next thing to parse (thus the error about A not being defined), while "A65" didn't match as a number, but eventually did as a string.

Your approach of using str_cmp() does work, in the sense that it will mark the correct answer correct, and incorrect answers as incorrect, but it will not report syntax errors, or type errors, or any of the other helpful things that MathObject will do for you. Also, you won't be able to enter expressions in hex (in case you were interested in that).

The better approach would be to make a context in which hexadecimal numbers were recognized. I was going to give you a basic layout for that, but got carried away and did the full thing myself. See the attached contextHex.pl file. To use it just set Context("Hex"), and then use $n = Compute('17A') or $n = Compute('A65'). From there, you use $n as a MathObject as usual (e.g., ANS($n->cmp)).

Note that this context included definitions for bitwise operators &, |, ^, >>, <<, and ~ (for "and", "or", "exclusive or", "shift right", "shift left" and "not"). You cause them in student answers, inside Compute() or in your PG code directly, (e.g., $m = $n & 0xFF).

Finally, to convert a perl integer to a hex MathObejct, use Hex(), as in $n = Hex(123) to convert the (decimal) number 123 into the equivalent of Compute('7B'). You can also use $n = Hex(0x7B) to do the same thing.

If you don't want to allow students to be able to perform computations within their answers, use Context("LimitedHex"), which disables all the operators (other than unary minus and commas for lists).

I hope that does what you need.