WeBWorK Problems

writing sequential problems

writing sequential problems

by Michael Gage -
Number of replies: 4
Hi Ken,
 I'm moving this question to the forum since there is a lot of interest
in writing sequential problems
(or compound problems or multipart problems -- we don't have a firm
naming convention yet).
It is posted at
http://wwrk.maa.org/moodle/mod/forum/discuss.php?d=349
You can set your preferences for this forum so that you are emailed whenever it is updated by going to http://wwrk.maa.org/moodle/mod/forum/view.php?f=3
and then choosing "subscribe to this forum".particular Karen Clark at TCNJ (who leads the AIM-WeBWorK work group on
sequential problems)and Davide Cervone have made contributions. I think the timing
is write and several people are interested in exploring the best way(s)
to construct these problems.
 As a starting point view the wiki document at 
 http://webwork.maa.org/wiki/SequentialProblems
--Mike
 
 On Jun 19, 2008, at 10:03 AM, Kenneth Appel wrote:
 Mike,
 I am trying to make what I used to call a sequential problem. In this
case, I want 11 answers before I check to see if the
last is correct before going on. I get a type of error that I do not
understand. There seem to be several possibility.
 perhaps A change in WeBWorK in the last few years means I should have
done something differently now than then.
-- there have been a number of changes and I expect that we can do
better than our original approaches to 
writing sequential problems.
 Here it is
Ken
 
set6: Problem 1
 This set is visible to students.
 Error messages
Not a CODE reference at line 76 of [TMPL]/msprobs6/ldintro.pg
Error details
 Problem1
ERROR caught by Translator while processing problem
file:msprobs6/ldintro.pg
****************
Not a CODE reference at line 76 of [TMPL]/msprobs6/ldintro.pg
****************
 ------Input Read
1 #DESCRIPTION
2 #ENDDESCRIPTION
3 
4 DOCUMENT();
5 loadMacros(
6 "PG.pl",
7 "PGbasicmacros.pl",
8 "PGchoicemacros.pl",
9 "PGanswermacros.pl",
10 "PGgraphmacros.pl",
11 "PGauxiliaryFunctions.pl",
12 );
13 TEXT(&beginproblem());
14 $showPartialCorrectAnswers = 1;
15 $ans2=2*13; 
16 $ans3=3*13; 
17 $ans4=4*13; 
18 $ans5=5*13; 
19 $ans6=6*13;
20 $ans7=7*13; 
21 $ans8=8*13; 
22 $ans9=9*13;
23 $ans10=52;
24 $ans11=4;
25 BEGIN_TEXT
26 $PAR
27 Long division may look complicated because a number of ideas are
combined to
28 make the work efficient. We will start by doing extra steps so that
it will
29 be easier to see what is happening.
30 $PAR
31 We will divide the number 6257 by 13. Remember that our answer will
be a quotient and a remainder. The quotient will be the largest number
of 13's in 6257. The remainder will be what remains after subtracting as
many 13's as we can from 6257.
32 $PAR
33 What we do is to find our quotient one digit at a time. This time we
will make a
34 \(help\ list\) but after a bit of practice you will probably decide
that you don't need one. Our help list will consist of the multiples of
13 up to \(9\times 13\)
35 $PAR
36 Help List
37 $BR
38 \(2\times 13=\)\{ans_rule(2)\}
39 $BR
40 \(3\times 13=\)\{ans_rule(2)\}
41 $BR
42 \(4\times 13=\)\{ans_rule(2)\}
43 $BR
44 \(5\times 13=\)\{ans_rule(2)\}
45 $BR
46 \(6\times 13=\)\{ans_rule(2)\}
47 $BR
48 \(7\times 13=\)\{ans_rule(2)\}
49 $BR
50 \(8\times 13=\)\{ans_rule(2)\}
51 $BR
52 \(9\times 13=\)\{ans_rule(2)\}
53 $PAR
54 Now that we have our help list, we look at the number 6257. The first
two digits are 62 and it has 2 more digits. So we find number in our
help list
 55 that is the largest number that is not more than 62. That number is
\\{ans_rule(2)\} which is \{ans_rule(1)\}\(\times 13\). Since there are
2 digits to the right of 62 in the number 6257 this means that
\{ans_rule(2)\}\(00\) which is \{ans_rule(2)\}\(00\times 13\) is the
largest multiple of 13 that ends with 00. 
 56 
57 
58 
59 $BR $BR \{NAMED_ANS_RULE('first_answer',10) \} 
60 END_TEXT
61 &ANS(str_cmp($ans2));
62 &ANS(str_cmp($ans3));
63 &ANS(str_cmp($ans4));
64 &ANS(str_cmp($ans5));
 65 &ANS(str_cmp($ans6));
66 &ANS(str_cmp($ans7));
67 &ANS(str_cmp($ans8));
68 &ANS(str_cmp($ans9));
69 
70 &ANS(str_cmp($ans10));
71 
72 $ans_eval1 = str_cmp($ans11);
73 NAMED_ANS(first_answer => $ans_eval1);
 74 $first_Answer = $inputs_ref->{first_answer}; 
75 
76 $rh_ans_hash1 = &$ans_eval1($first_Answer);
77 #because it is text it is handled differently
78 
79 # Using named answers allows for more control. Any unique label can
be 
 80 # used for an answer. 
81 # (see
http://cartan.math.rochester.edu/WeBWorKdiscussion/discuss/msgReader$13 
82 # for more details on answer evaluator formats and on naming answers
83 # so that you can refer to them later. Look also at the pod
documentation in 
 84 # PG.pl and PGbasicmacros.pl which you can also reach at 
85 #
http://webwork.math.rochester.edu/docs/techdescription/pglanguage/index.
html)
86 
87 # Check to see that the first answer was answered correctly. If it
was then we
 88 # will ask further questions. 
89 # We need to know what the answer was named.
90 
91 #$rh_ans_hash1 = $ans_eval1->evaluate($first_Answer);
92 
93 # warn pretty_print($rh_ans_hash); # this is useful error technique
 94 
95 # The output of each answer evaluator consists of a single %ans_hash
with (at 
96 # least) these entries: 
97 # $ans_hash{score} -- a number between 0 and 1 
98 # $ans_hash{correct_ans} -- The correct answer, as supplied by the
instructor
 99 # $ans_hash{student_ans} -- This is the student's answer 
100 # $ans_hash{ans_message} -- Any error message, or hint provided by 
101 # the answer evaluator. 
102 # $ans_hash{type} -- A string indicating the type of answer
evaluator. 
 103 # -- Some examples: 
104 # 'number_with_units' 
105 # 'function' 
106 # 'frac_number' 
107 # 'arith_number' 
108 # For more details see 
 109 #
http://cartan.math.rochester.edu/WeBWorKdiscussion/discuss/msgReader$15 
110 
111 # If they get the first answer right, then we'll ask a second part
to the 
112 # question ...
113 
114 if (1 == $rh_ans_hash1->{score} ) {
 115 
116 # WATCH OUT!!: BEGIN_TEXT and END_TEXT have to be on lines by 
117 # themselves and left justified!!! This means you can't indent 
118 # this section as you might want to. The placement of BEGIN_TEXT
 119 # and END_TEXT is one of the very few formatting requirements in
120 # the PG language.
121 
122 BEGIN_TEXT 
123 $PAR 
124 We got here.
125 END_TEXT
126 }
127 END_DOCUMENT
In reply to Michael Gage

Re: writing sequential problems

by Michael Gage -
This won't be perfect, but the code below gives you a framework for
writing sequentialProblems. You will need to do to obtain file
 "compoundProblem.pl",

which Davide Cervone wrote last August. You can download this
and related files from the link on http://webwork.maa.org/wiki/SequentialProblems

Or you can type
cvs update
in the pg/macros directory


Reading the top of that file will give you instructions
on modifications that are possible with this
version of sequential problems.

One of the "features" is that once you have completed one
section of the problem you can't return to the earlier sections.
We'd like to modify that behavior but it may not happen right away.

##DESCRIPTION
## Algebra problem: true or false for inequality
##ENDDESCRIPTION

##KEYWORDS('algebra', 'inequality', 'fraction')

## DBsubject('Algebra')
## DBchapter('Fundamentals')
## DBsection('Real Numbers')
## Date('6/3/2002')
## Author('')
## Institution('')
## TitleText1('Precalculus')
## EditionText1('3')
## AuthorText1('Stewart, Redlin, Watson')
## Section1('1.1')
## Problem1('22')

########################################################################

DOCUMENT();

loadMacros(
 "PGstandard.pl", # Standard macros for PG language
 "MathObjects.pl",
 "compoundProblem.pl",
 "unionLists.pl",
 #"source.pl", # allows code to be displayed on certain sites.
 #"PGcourse.pl", # Customization file for the course
);

# Print problem number and point value (weight) for the problem
TEXT(beginproblem());

# Show which answers are correct and which ones are incorrect
$showPartialCorrectAnswers = 1;

##############################################

$isProfessor = ($studentLogin eq 'dpvc' || $studentLogin eq 'professor');

#
# Start a compound problem. See the compoundProblem.pl
# file for more details about the parameters you
# can supply.
#
$cp = new compoundProblem(
 parts => 3, # the total number of parts in this problem
 totalAnswers => 4, # total answers in all parts combined
 parserValues => 1, # make parser objects from student answers
 allowReset => $isProfessor, # professors get Reset button for testing
);
$part = $cp->part; # look up the current part

##############################################
#
# Part 1
#

if ($part == 1) {

##############################################
##############################################################
#
# Setup
#
#
Context("Numeric");
Context()->flags->set(reduceConstants=>0);

$ans[2] = Formula("2*13");
$ans[3] = Formula("3*13");
$ans[4] = Formula("4*13");
$ans[5] = Formula("5*13");
$ans[6] = Formula("6*13");
$ans[7] = Formula("7*13");
$ans[8] = Formula("8*13");
$ans[9] = Formula("9*13");
$ans[10] = Formula("52");
$ans[11] = Formula("4");

##############################################################
#
# Text
#
#

Context()->texStrings;
BEGIN_TEXT
$PAR
 Long division may look complicated because a number of ideas are combined to
make the work efficient. We will start by doing extra steps so that it will
be easier to see what is happening.
$PAR
We will divide the number 6257 by 13. Remember that our answer
will be a quotient and a remainder. The quotient will be the largest
number of 13's in 6257. The remainder will be what remains after
subtracting as many 13's as we can from 6257.
$PAR
Help List
\{ BeginList("OL")\}
END_TEXT


 foreach $j (2..11) {
 TEXT(EV3(q! $ITEM \\( $ans[$j] = \\) \\{ ans_rule(20)\\} ! ));
 }

BEGIN_TEXT

\{ EndList("OL") \}
$PAR
Now that we have our help list, we look at the number 6257.
The first two digits are 62 and it has 2 more digits.
So we find number in our help list
that is the largest number that is not more than 62.
That number is
\{ans_rule(2)\} which
is
\{ans_rule(1)\}\(\times 13\). Since there are 2 digits to t
he right of 62 in the number 6257 this means
that
\{ans_rule(2)\}\(00\) which is
\{ans_rule(2)\}\(00\times 13\) is
the largest multiple of 13 that ends with 00.




END_TEXT
Context()->normalStrings;

# $BR $BR \{NAMED_ANS_RULE('first_answer',10) \}
##############################################################
#
# Answers
#
#
Context("LimitedNumeric");
foreach $j (2..11) {
 # convert to an object that requires an integer answer
 ANS(Real($ans[$j])->cmp);
}
ANS(Real(52)->cmp,Real(4)->cmp,Real(4)->cmp,Real(52)->cmp);

} # End of Part 1

##############################################
#
# Part 2
#

if ($part == 2) {

$a = 3;
$b = 4;
BEGIN_TEXT
Part 2:
$PAR
\($a + $b\) = \{ans_rule(10)\}
END_TEXT
$c = $a+$b;
ANS(num_cmp($c,mode=>"strict"));

}

##############################################
#
# Part 3
#

if ($part == 3) {

$f = Formula("$a x + $b")->reduce;

BEGIN_TEXT
Part: 3:
$PAR
Suppose \(f(x) = \{$f->TeX\}\).$BR
Then \(f(2)\) = \{ans_rule(10)\}.
END_TEXT

ANS($f->eval(x=>2)->cmp);

}

##############################################
ENDDOCUMENT();

In reply to Michael Gage

Re: writing sequential problems

by Michael Gage -

Difficulty 1 is that I do not know how to reset the problem. I am getting around this temporarily by creating a student named
tester who is working the problem for the first time.

This is a known problem of the current implementation. For the professor you can fix it by changing these lines in the
question:

##############################################
$isProfessor = ($studentLogin eq 'dpvc' || $studentLogin eq 'professor');
#
# Start a compound problem. See the compoundProblem.pl
# file for more details about the parameters you
# can supply.
#
$cp = new compoundProblem(
 parts => 3, # the total number of parts in this problem
 totalAnswers => 4, # total answers in all parts combined
 parserValues => 1, # make parser objects from student answers
 allowReset => $isProfessor, # professors get Reset button for testing
);

Changing
allowReset => 1 

will give everyone a reset button -- this might be the best compromise for now. Further work needs to be done to determine exactly how one wants a sequential problem to behave.

Should the student be able to see earlier work? to change it? What is the desired behavior?

You can also change the line above:

isProfessor = ($studentLogin eq 'dpvc' || $studentLogin eq 'professor');

to contain your login instead of Davide's.

In reply to Michael Gage

Re: writing sequential problems

by Michael Gage -
There was a typo: a ! in the link when it was copied over from the previous wiki. It's fixed now.

-- Mike