NAME

scaffold.pl - Provides support for multi-part problems where later parts are not visible until earlier parts are completed correctly.

DESCRIPTION

Scaffolding macros provide the ability to make a single problem file contain multiple parts, where the later parts aren't visible to the student until the earlier ones are completed. The author has control over which parts are allowed to be opened, and which are showing, but does not have to keep track of what answer blanks go with which sections (as was the case in the earlier compoundProblem macros). It is even possible to have nested scaffolds within a single problem.

To use the scaffolding macros, include the macros into your problem

loadMacros("scaffold.pl");

and then use Scaffold::Begin() to start a scaffold problem and Scaffold::End() to end it. In between, use Section::Begin(title) and Section::End() around the sections of your problem. Within a section, use BEGIN_TEXT/END_TEXT or BEGIN_PGML/END_PGML to create the text of the section as usual, and ANS() to assign answer checkers to the blanks that appear within the section. For example:

Scaffold::Begin();

Section::Begin("Part 1: The first part");
BEGIN_TEXT
This is the text for part 1.  \(1+1\) = \{ans_rule\}
END_TEXT
ANS(Real(2)->cmp);
Section::End();

Section::Begin("Part 2: The second part");
BEGIN_TEXT
This is text for the second part.  \(2*2\) = \{ans_rule\}
END_TEXT
ANS(Real(4)->cmp);
Section::End();

Scaffold::End();

You can include whatever code you need to between the Section::Begin() and Section::End() calls, so you can create variables, set the Context, perform computations, generate text sections, and so on. Whatever answer checkers are assigned within a section are the ones that are used to decide when that section can be opened by the student. Any solutions created within a section become part of that section, and will be made available from within that section, when applicable.

A section is considered to be "correct" when all the answers contained in it are correct. Note that essay answers are treated specially, and are always considered correct (when non-empty) for purposes of determining when a section is correct. You can also force a non-empty answer blank to be considered correct by using the scaffold_force option on the answer checker. For example:

ANS(Real(123)->cmp(scaffold_force => 1));

would mean that this answer would not have to be correct for the section to be considered correct.

Note that you can also create text (or even answer blanks and checkers) between the sections, or before the first one, or after the last one, if you wish. That material would always be showing, regardless of which sections are open. So, for example, you could put a data table in the area before the first section, so that it would be visible throughtout the problem, no matter which section the student is working on.

The Scaffold::Begin() function accepts optional parameters that control the functioning of the scaffold as a whole. The primary use it to control when the sections can be opened by the student, and which is currently open. The following options are provided:

can_open => condition

This specifies when a section can be opened by the student. The condition is either one of the strings "always", "when_previous_correct", "first_incorrect", "incorrect" or "never", or is a reference to a subroutine that returns 0 or 1 depending on whether the section can be opened or not (the subroutine is passed a reference to the section object). The default value is "when_previous_correct", which means that all the correct sections and the first section incorrect or empty blanks would be able to be opened by the student. The value "first_incorrect" would mean that correct sections can not be reopened, and only the first one that is not fully correct can be, while "incorrect" means that only incorrect sections can be opened (so once a section is correct, it can't be reopened). The value "always" means the student can always open the section, and "never" means that the section can never be opened.

If answers are available (i.e., it is after the answer date), then the after_AnswerDate_can_open option (described below) is used instead of this option. If not and the user is a professor, then the instructor_can_open option (described below) is used instead.

is_open => condition

This is similar to the can_open option above, but determines whether the section will be open when the problem is displayed. The possible values are "always", "incorrect", "first_incorrect", "correct_or_first_incorrect", "never", or a reference to a subroutine that returns 0 or 1 depending on whether the section should be open or not (the subroutine is passed a reference to the section object). Note that a section will only open if the can_open condition is also met, so you do need to coordinate these two values. The default is "first_incorrect", which means that only the first section with incorrect answers will be open when the problem is displayed after answers are submitted (though the student may be abe to open other sections afterward, depending on the value if can_open. The value "incorrect" would mean that all incorrect or incomplete sections are open (the student can see all future work that he or she must complete) but correct sections are closed, while "correct_or_first_incorrect" would be the opposite: all correct sections and the first incorrect one are opened while the later sections are closed (the student can see the completed work, but not the future sections). As expected, "always" would mean every section that can be opened will be open, and "never" means no section is opened.

Hardcopy versions of the problem use the hardcopy_is_open option (described below).

instructor_can_open => condition

This provides the condition for when an instructor (as opposed to a student) can open a section. By default, this is set to "always", so that instructors can look at any section of the problem, but you can set it to any value for can_open above. If you are an instructor and want to test how a problem looks for a student, you can set

$Scaffold::isInstructor = 0;

temporarily while testing the problem. Remember to remove that when you are done, however.

after_AnswerDate_can_open => condition

This is similar to the can_open option (described above), and is used in place of it when the answers are available. The default is "always". That means that after the answer date, the student will be able to open all the sections regardless of whether the answers are correct or not.

hardcopy_is_open => condition

This is similar to the is_open option (described above), and is used in place of it when the problem appears in hardcopy output. The default is "always", which means that any sections that can be open will be open in hardcopy output. This allows the student to see the parts of the problem that are already complete, even if they don't open when viewed on line.

open_first_section => 0 or 1

This determines whether the initial section is open (when it can be). With the default can_open and is_open settings, the first section will be open automatically when the problem is first viewed, but if you have material to read (or even answers to give) prior to the first section, you might want the first section to be closed, and have the student open it by hand before anwering the questions. In this case, set this value to 0 (it is 1 by default).

numbered => 0 or 1

This determines whether each section is automatically numbered before its title. If true, each section title will be preceded by a number and a period. The section's nesting level determines the style of numbering: a, i, A. Any deeper and numbering is just arabic. If there is no title, a default title like "Part 1:" is used, and in that case no extra numbering is added regardless of this option.

Some useful configurations are:

The defaults: only the active section is open, but students can open previous correct sections if they want.

Scaffold::Begin(
    can_open => "when_previous_correct",
    is_open  => "first_incorrect"
);

Sections stay open as the student works through the problem.

Scaffold::Begin(
    can_open => "when_previous_correct",
    is_open  => "correct_or_first_incorrect"
);

Students work through the problem seeing only one section at a time, and can't go back to previous sections.

Scaffold::Begin(
    can_open => "first_incorrect",
    is_open  => "first_incorrect"
);

Students can view and work on any section, but only the first incorrect one is shown initially.

Scaffold::Begin(
    can_open => "always",
    is_open  => "first_incorrect"
);

Students see all the parts initially, but the sections close as the student gets them correct.

Scaffold::Begin(
    can_open => "always",
    is_open  => "incorrect"
);

Students see all the parts initially, but the sections close as the student gets them correct, and can't be reopened.

Scaffold::Begin(
    can_open => "incorrect",
    is_open  => "incorrect"
);

The Section::Begin() macro also accepts the options can_open, is_open, and instructor_can_open described above. This allows you to override the defaults for a particular section. In particular, you can provide a subroutine that determines when the section can or should be open.

Note that values like $showPartialCorrectAnswers and the isntalled grader are global to the whole problem, so can't be set individually on a per section basis. Also note that the answers aren't checked until the end of the problem, so any changes you make to the Context() after a section is ended will still affect the context within that section.