|
The free-response portion of the Advanced Placement test in Computer Science
(APCS test) is difficult, particularly in light of the time allowed for its
completion. Doubtless even experienced programmers might find it hard to achieve
full or nearly full credit. Scores can be improved, however, by applying good
test-taking strategy, by employing specific techniques applicable to programming
generally, and by using common sense.
I offer below some practical test-taking advice to students planning to sit
for the APCS test, given from the point of veiw of a Reader of that examination.
Application of these suggestions will not compensate for poor preparation, of
course, but it should help students improve their scores by helping them show
more clearly what they know and what they can do. Much of my advice can be
applied to any of the free-response questions, though some of it is specific to
problems requiring Pascal code. In fact, many of these ideas can be applied by
any student taking a test on which code is called for. I conclude with some
related suggestions for teachers of the APCS course.
Advice to Students: How to
Score As High As Possible
My first piece of advice is a standard test-taking suggestion—read all
the problems before answering any of them. This advice is practical for the
free-response section of the APCS test, as there are only a handful of problems.
Although questions are sometimes easier or more difficult than they first
appear, a quick appraisal of the entire test usually will allow you to make a
reasonable estimate of how much time and effort you should devote to each item.
Since all questions on the test are weighted equally, it makes sense to answer
the easier ones first. Having an overview of the examination will help you avoid
spending too much time on any problem, thereby leaving too little time for the
remaining ones. Checking over the entire test booklet also provides insurance
against difficulties resulting from very rare (but not unknown) printing errors.
Identifying duplicate or missing pages immediately can save valuable time. When
you eventually read a question in order to answer it, you will be giving that
problem a second reading, and you should be better prepared to provide a
correct response than if you had read it but once.
Allocation of your time among the problems should be influenced not only by
your appraisal of your own capabilities and problem difficulties, but also by
your knowledge of the test as a whole. The examination is designed to measure a
broad range of knowledge and skill, as outlined in the booklet “AP Course
Description in Computer Science.” Individual questions have specific primary
objectives, however, and can be expected to be scored with different emphases.
For a question requiring the writing of a brief, straightforward program, you
can reasonably expect that errors of syntax, documentation, formatting, or
modular design will be heavily penalized. Such mechanics will likely be given
only minor scoring emphasis on a problem requiring you to generate and implement
a complex algorithm. Keep these matters in perspective. Avoid doing a slapdash
job on an easy problem or spending excessive time converting a good response to
a difficult problem into a splendid one.
It is sometimes helpful to ask what the test writers seem to be looking for.
Although you have a right to expect that questions be reasonably explicit, many
questions in the past have stopped short of saying “write it this way,” yet have
strongly implied that some particular technique (such as writing a
likely-to-be-changed calculation as a function) is to be used. You are
well-advised to take obvious hints and not seek perverse rationale for
alternative approaches. In particular, an argument can almost always be made for
not using procedures or functions in the short fragments of code required
on the APCS test. Since you will not be around to state your case when your
answer is being scored, however, modularize your code if the question at all
suggests that you should.
When answering questions on the APCS examination, students sometimes err on
the side of writing too much. Do not write code to perform unnecessary
operations. If you are asked to find the largest value stored in an array, for
example, do not first read values into the array from an input file. To do so is
not only to waste time, but to sacrifice the correctness of your answer. If the
array is already filled with the values to be processed, to read in a new set of
values before finding the maximum is to solve the wrong problem!
Avoid the temptation to show off, by using recursion to do something easily
done iteratively, for example. If the test designers want you to do something
fancy, their intention will be made clear. The most obvious danger of trying to
be clever is that you might make errors. Even if you avoid this peril, you run
the risk that an offbeat solution may be scored incorrectly. (Yes, Readers are
human and can misinterpret your answers. The scoring process is designed to
minimize this, but mistakes can be made, especially if the code is obscure or
poorly commented.) Finally, you may be subjected to point deductions for
inefficiency, inappropriateness, or lack of clarity. This is not to say that
displays of cleverness on the examination are punished. For many good reasons,
however, disciplined programmers attempt to produce straightforward code
whenever possible, resorting to non-obvious devices or advanced techniques only
when they are clearly needed, often only after more conventional approaches have
failed to satisfy fully the program requirements.
Although you should not go out of your way to display everything you know,
neither should you be reluctant to demonstrate knowledge which is clearly
relevant. Certain components of your answer are usually assigned a fixed number
of points. One point might be allocated to the procedure statement, for example.
This means that if you can write an acceptable procedure statement, even if you
have no idea what code should go inside the procedure, you can increase your raw
score by doing so. Similar advice applies to declarations. Recognition that
certain variables of particular types are required to solve the problem at hand
is a significant indicator of programming competence. Declare needed variables,
even if you do not show or show correctly how they are to be used. Also, if you
know what a segment of code needs to do but cannot seem to write it, communicate
your understanding by means of a comment or invoke an incomplete procedure to
perform the required operation. In so doing, you illustrate your grasp of the
algorithm as a whole, even though you are unable to supply the implementation
details. Remember that a blank response represents a certain zero score for the
question. You should not waste a Reader’s time with nonsense, but meaningful
statements relevant to the solution can rightfully earn some credit.
After answering each problem, there are several checks you should make.
First, be sure the Reader can find your answer. Mark out any irrelevant scratch
work or false starts, since if you appear to have given two answers, the first
will be scored and the second ignored, even if the second is “clearly” your
intended response. Be sure you indicate where your answer is located if it is
not on the page where it is expected. The scoring process probably catches all
misplaced responses, but why take any chances? If you use extra pages for your
answers, be sure each carries a preprinted test number label and is stapled into
the test booklet when the booklet is turned in. Where Pascal code is called for,
do a quick check of mechanics—are begin’s matched with end’s,
semicolons properly placed, prompts written where terminal input is required,
comments included to provide documentation, all variables declared, parameters
declared var where appropriate, and so forth. Next, be sure you have
fulfilled all requirements of the problem. For example, if a procedure is called
for, is your answer actually in the form of a procedure? If a question has
several parts, have all of them been answered? Be especially careful to check
for unstated but implied requirements. For example, will your linked-list
procedure work on an empty list as well as a nonempty one?
Given that your answer addresses all requirements of the question, is it
correct? Answers on the test often show little evidence that the writer examined
the code after writing it. A quick rereading can uncover mistakes and
inconsistencies, such as loops with incorrect or missing initialization and
off-by-one errors. If time permits, code should be traced with representative
and perhaps even extreme test data. Question 2 from the 1985 test can be used to
illustrate the kind of error which is often missed, but which can be caught
through tracing:
2. A circularly linked list contains
nodes defined by:
type
Ptr =
^Node;
Node = record
Datum : integer;
Link : Ptr
end;
Suppose p is of type Ptr and points to a node in a circularly linked list
with an unknown but even number of nodes. You are to write a procedure that will
break the list into two disjoint circularly linked lists each containing exactly
half the nodes from the original list. Pointer p should point to a node in one
list, and a new pointer q should point to a node in the other. The choice of
which nodes to include in which list is up to you. Your procedure should begin
with a few comments to describe how it works.
The code below for manipulating the lists almost works.
(We ignore the possibility that p points to a null list.)
pstart := p;
q := p^.link;
repeat
p^.link
:= q^.link;
p :=
p^.link;
q^.link
:= p^.link;
q :=
q^.link
until p=pstart
The student who wrote this probably did draw some
pictures and trace the code, but did not trace it far enough. The problem is
that on the last time through the loop, the assignment to q^.link is incorrect
because p no longer points to the second node of the list. This error is easily
found, but only if the code is traced from beginning to end. To appreciate the
mistake, try doing so yourself for a 2- or 4-node list.
Correcting this problem requires that pointers be
maintained to the starting modes of both lists. The loop needs to terminate
one iteration earlier than in the original solution, after which the ends of the
lists can be properly connected:
pstart := p;
qstart :=
p^.link;
q := qstart;
while q^.link<>pstart
do
begin
p^.link :=
q^.link;
p :=
p^.link;
q^.link :=
p^.link;
q
:= q^.link
end;
p^.link := pstart;
q^.link := qstart
Some Ideas for Teachers
Teachers, of course, can help their students by
communicating to them the above suggestions. Students need experience applying
these strategies, however, so that tests resembling the free-response portion of
the APCS examination should be given from time to time. To best simulate
conditions of the examination, a grading scheme should be constructed in advance
and should be as objective as possible. (Since dozens of people are involved in
grading the APCS examination, requirements for reliability necessarily limit the
use of subjective evaluation.)
The conventional wisdom is that program-writing tests
are prone to give capricious results, as “the right trick” may not occur even to
a talented student, and the errors which invariably are made make it difficult
to separate the totally muddled answer from the slightly wrong one. If students
will apply the test-taking strategies suggested, however, the reliability of
such tests should be improved. In any case, on your trial tests, try to pose
questions whose answers require programming and problem-solving skills and
understanding of computer science concepts, rather than inspiration.
Encourage your students in the use of a variety of
techniques to verify program correctness. They should be adept at determining
that first and final transits of loops perform the correct operations, for
instance. Emphasize formal desk checking of program execution, particularly for
recursive code and code involving pointers or complex data structures. Be sure
your students can draw diagrams of typical linked list structures and use them
in program traces.
Make your students aware of the APCS course syllabus.
They need to know what the test designers consider important. Students can
easily underestimate the importance placed on comments, modularization, prompts,
and properly labeled output.
Although professional programming is not a timed
activity, the time pressures on the programmer are very real. The
suggestions I have made encourage care and aim at minimizing the effects of
inevitable errors. Students who apply these strategies in the right spirit will
likely score higher on the APCS test and become better programmers, and may even
find that these lessons can be applied to other intellectual activities.
|