Remove the redundant file headers.
[mdwtools] / exercise.dtx
CommitLineData
86f6a31e 1% \begin{meta-comment} <general public licence>
2%%
3%% exercise package -- useful macros for setting exercises with answers
db127fce 4%% Copyright (c) 2003 Mark Wooding
86f6a31e 5%%
6%% This program is free software; you can redistribute it and/or modify
7%% it under the terms of the GNU General Public License as published by
8%% the Free Software Foundation; either version 2 of the License, or
9%% (at your option) any later version.
e8e9e5d8 10%%
86f6a31e 11%% This program is distributed in the hope that it will be useful,
12%% but WITHOUT ANY WARRANTY; without even the implied warranty of
13%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14%% GNU General Public License for more details.
e8e9e5d8 15%%
86f6a31e 16%% You should have received a copy of the GNU General Public License
17%% along with this program; if not, write to the Free Software Foundation,
18%% Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19% \end{meta-comment}
20%
21% \begin{meta-comment} <Package preambles>
22%<+package>\NeedsTeXFormat{LaTeX2e}
23%<+package>\ProvidesPackage{exercise}
db127fce 24%<+package> [2003/08/25 1.1 Exercies with answers]
86f6a31e 25% \end{meta-comment}
26%
db127fce 27% \CheckSum{271}
86f6a31e 28%% \CharacterTable
29%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
30%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
31%% Digits \0\1\2\3\4\5\6\7\8\9
32%% Exclamation \! Double quote \" Hash (number) \#
33%% Dollar \$ Percent \% Ampersand \&
34%% Acute accent \' Left paren \( Right paren \)
35%% Asterisk \* Plus \+ Comma \,
36%% Minus \- Point \. Solidus \/
37%% Colon \: Semicolon \; Less than \<
38%% Equals \= Greater than \> Question mark \?
39%% Commercial at \@ Left bracket \[ Backslash \\
40%% Right bracket \] Circumflex \^ Underscore \_
41%% Grave accent \` Left brace \{ Vertical bar \|
42%% Right brace \} Tilde \~}
43%%
44%
45% \begin{meta-comment}
46%
47%<*driver>
48\input{mdwtools}
49\describespackage{exercise}
50\let\epsilon\varepsilon
db127fce 51\errorcontextlines\maxdimen
86f6a31e 52\mdwdoc
53%</driver>
54%
55% \end{meta-comment}
56%
57%^^A-------------------------------------------------------------------------
58% \section{User guide}
59%
60% The \package{exercise} package allows you to typeset exercises and keep the
61% answers together with the questions in your source (so they don't get
62% lost) but typeset them all together at the end of your document.
63%
64% \subsection{Exercises and answers}
65%
66% \DescribeEnv{exercise}
67% Exercises are typset in an \env{exercise} environment. This takes no
68% arguments. There's a counter for exercises, named |exercise|, and you can
69% cross-reference exercises in the usual way.
70%
71% \DescribeMacro\answer
72% If you want to include an answer for your exercise, just say |\answer|
73% followed by your answer. The rest of the text up to the end of the
74% \env{exercise} environment is considered to be the answer, and is stored
75% away until asked for. This material can contain anything you like. It
76% \emph{isn't} a moving argument.
77%
78% \begin{figure}
79%\begin{demo}[w]{The \env{exercise} environment}
80%\begin{exercise}
81%Show that if $F\colon \{0, 1\}^k \times \{0, 1\}^* \to \{0, 1\}^L$
82%is a $(t, q + 1, \epsilon)$-secure PRF, then $F$~is also a
83%$(t, q, \epsilon + 2^{-L})$-secure MAC.
84%\answer
85%Let~$A$ be an adversary attacking~$F$ as a MAC. Consider the
86%adversary~$B$ \ldots
87%\end{exercise}
88%\end{demo}
89% \end{figure}
90%
db127fce 91% \DescribeMacro\skipanswer
92% The |\skipanswer| command is similar, but just skips over the answer rather
93% than writing it to the output file. It does nothing at all with counters
94% -- it's as if there was no answer given at all.
95%
96% It's OK to use commands like |\answer| and |\skipanswer| in your own
97% macros as long as they're the \emph{last} token. You can therefore say
98% something like
99%\begin{verbatim}
100%\newcommand{\evenanswer}{%
101% \ifthenelse%
102% {\isodd{\value{exercise}}}%
103% {\answer}%
104% {\skipanswer}%
105%}
106%\end{verbatim}
107% to get just the answers to the odd-numbered problems. (If you don't like
108% \package{ifthen} then you'll need to play with |\expandafter| for a bit.)
109%
86f6a31e 110% \subsection{The answers file}
111%
112% \DescribeMacro\answrite
113% Answers are accumulated into a file, to be read later. Additional material
114% can be added to the file using the |\answrite| macro, which just writes its
115% argument. Note that this is a \emph{moving} argument, so fragile commands
116% need |\protect|ing.
117%
118% \DescribeMacro\exctrcheck
119% It's common to divide up the answers by section. You can tell the package
120% to check a collection of counters and perform actions if they've changed
121% since last time, giving you a chance to write the correct decorations to
122% the answers file. This is done by saying
123% \syntax{"\\exctrcheck{"<counter>"}{"<action>"}"}. Then, each |\answer|
124% command checks to see if \<counter> has changed since last time, and if it
125% has, it does \<action>, For example,
126%\begin{verbatim}
127%\exctrcheck{section}
128% {\answrite{\protect\subsection*{Section \thesection}}}
129%\end{verbatim}
130% starts a new (unnumbered) subsection in the answers for each section in the
131% main document.
132%
133% \subsection{Style tweaks}
134%
135% The \env{exercise} environment is very simple, and can be easily rewritten
136% to fit in with your style preferences. If you like exercises to look like
137% theorems, the easiest thing to do is say something like
138%\begin{verbatim}
139%\newtheorem{doexercise}[exercise]{\exercisename}
140%\renewenvironment{exercise}{\exfix\doexercise}{\enddoexercise}
141%\end{verbatim}
142% This makes the environment use the existing exercise counter. If you don't
143% want that, say
144%\begin{verbatim}
145%\newtheorem{doexercise}[othercounter]{\exercisename}
146%\renewenvironment{exercise}{\exfix\doexercise}{\enddoexercise}
147%\let\theexercise\theothercounter
148%\end{verbatim}
149% and all will be well.
150%
151% \DescribeEnv{doanswer}
152% Answers are typeset in a \env{doanswer} environment, which is given one
153% argument: the exercise number (as set by |\theexercise|). This can be
154% modified to do whatever you like.
155%
156% \DescribeMacro\exfix
157% The |\exfix| is a convenient hook which is run both in the \env{exercise}
158% and \env{doanswer} environments by default. The current implementation
159% just skips a level of \env{enumerate} depth, which usually means that
160% \env{enumerate} lists will go (a), (b), (c), \ldots\ rather than 1, 2, 3,
161% \ldots
162%
163% \subsection{Lists in paragraphs}
164%
165% \DescribeEnv{parenum}
166% Answers to subparts tend to be compressed together into a single
167% paragraph. It's nice, when you do this, not to have to worry about losing
168% your numbering of subparts. The \env{parenum} environment provides an
169% enumerated list in a paragraph. So, for example, you can say something
170% like this.
171%\begin{demo}[w]{Example of \env{parenum}}
172%\begin{exercise}
173%A PRG $g\colon \{0, 1\}^k \to \{0, 1\}^L$ is \emph{trivial} if
174%$k \ge L$.
175%\begin{enumerate}
176%\item Show that trivial PRGs exist.
177%\item Show that a non-trivial $(t, \epsilon)$-secure PRG is a
178% $(t, \epsilon + 2^{k-L})$-secure one-way function.
179%\end{enumerate}
180%\answer
181%\begin{parenum}
182%\item The identity function is a trivial PRG: the real and random
183% games are identically distributed.
184%\item Let~$A$ be an adversary attempting to invert~$g$: then we
185% can construct a distinguisher~$B$ as follows \ldots
186%\end{parenum}
187%\end{exercise}
188%\end{demo}
189%
190% \subsection{And finally}
191%
192% \DescribeMacro\answers
193% In order to extract your answers, say |\answers|.
194%\begin{demo}[w]{The \texttt{\string\answers} command}
195%\section*{Answers}
196%\answers
197%\end{demo}
198%
db127fce 199% The |\answers| command has an optional argument, which is the file to read
200% in. This allows you to make `answer booklet' documents, by saying
201% something like
202%\begin{verbatim}
203%\answers[otherdoc]
204%\end{verbatim}
205% If you don't give a file extension, then |.ans| is appended automatically.
206%
86f6a31e 207% \implementation
e8e9e5d8 208%
86f6a31e 209%
210%^^A-------------------------------------------------------------------------
211% \section{Implementation}
212%
213% \begin{macrocode}
214%<*package>
215% \end{macrocode}
216%
217% \subsection{Initialization}
218%
db127fce 219% The \textsf{within} option is handled by the \package{mdwkey} package.
86f6a31e 220%
221% \begin{macrocode}
db127fce 222\RequirePackage{mdwkey}
86f6a31e 223% \end{macrocode}
224%
225% \begin{macro}{\ex@within}
226%
227% When the \textsf{within} option is seen, we set a command |\ex@within| to
228% the correct code, to be executed later when we've made our minds up.
229%
230% \begin{macrocode}
231\let\ex@within\relax
db127fce 232\mkdef{exercise:opts}{within}{%
86f6a31e 233 \def\ex@within{%
234 \@addtoreset{exercise}{#1}%
235 \toks@\expandafter{\csname the#1\expandafter\endcsname%
236 \expandafter.\theexercise}%
237 \edef\theexercise{\the\toks@}%
238 }%
239}
240% \end{macrocode}
241% \end{macro}
242%
243% \begin{macro}{\ex@opts}
244%
db127fce 245% The |\ex@opts| macro just runs the \package{mdwkey} kit to parse an option
86f6a31e 246% string.
247%
248% \begin{macrocode}
db127fce 249\def\ex@opts{\mkparse{exercise:opts}}
86f6a31e 250% \end{macrocode}
251% \end{macro}
252%
253% Now do the options thing.
254%
255% \begin{macrocode}
256\DeclareOption*{\expandafter\ex@opts\expandafter{\CurrentOption}}
257\ProcessOptions*
258% \end{macrocode}
259%
260% Set up the |exercise| counter, and number it within some other sort of
261% counter as appropriate.
262%
263% \begin{macrocode}
264\newcounter{exercise}\ex@within
265% \end{macrocode}
266%
267% We also need the \package{sverb} package in order to do the delaying of the
268% answers.
269%
270% \begin{macrocode}
271\RequirePackage{sverb}
272% \end{macrocode}
273%
274% \subsection{Checking for counter changes}
275%
276% \begin{macro}{\ex@ctrcheck}
277%
278% The counter checking state is stored here. It's initially empty.
279%
280% \begin{macrocode}
281\def\ex@ctrcheck{}
282% \end{macrocode}
283% \end{macro}
284%
285% \begin{macro}{\exctrcheck}
286%
287% Adding a counter to the check list is relatively easy. We expand the
288% current list into a token register, add the new material to the end, and
289% put the list back in our macro using |\edef|. The `last' value of the
290% counter is set to |\relax|, to force out the change on the next |\answer|.
291%
292% \begin{macrocode}
293\def\exctrcheck#1#2{%
294 \toks@\expandafter{\ex@ctrcheck\ex@ctrdo{#1}{#2}}%
295 \edef\ex@ctrcheck{\the\toks@}%
296 \global\expandafter\let\csname ex@ctrlast@#1\endcsname\relax%
297}
298% \end{macrocode}
299% \end{macro}
300%
301% \begin{macro}{\ex@ctrdo}
302%
303% Here we actually check to see whether a counter has changed and execute the
304% appropriate code.
305%
306% \begin{macrocode}
307\def\ex@ctrdo#1#2{%
308 \edef\@tempa{\csname the#1\endcsname}%
309 \expandafter\ifx\csname ex@ctrlast@#1\endcsname\@tempa\else%
310 #2%
311 \global\expandafter\let\csname ex@ctrlast@#1\endcsname\@tempa%
312 \fi%
313}
314% \end{macrocode}
315% \end{macro}
316%
317% \subsection{The \env{exercise} environment}
318%
319% \begin{macro}{\exercisename}
320%
321% We store the string to print for each exercise in |\exercisename| as a
322% half-hearted attempt at internationalization.
323%
324% \begin{macrocode}
325\providecommand\exercisename{Exercise}
326% \end{macrocode}
327% \end{macro}
328%
329% \begin{macro}{\exfix}
330%
331% This is a dumping ground for style fixing common to both exercises and
332% answers. Here, we bump on the \env{enum} depth counter, so that it skips
333% labelling with digits.
334%
335% \begin{macrocode}
336\def\exfix{\advance\@enumdepth\@ne}
337% \end{macrocode}
338% \end{macro}
339%
340% \begin{environment}{exercise}
341%
342% This is pretty simple. The environment is list-based, with the number set
343% in bold in a label.
344%
345% \begin{macrocode}
346\def\exercise{%
347 \refstepcounter{exercise}%
348 \exfix%
349 \trivlist\advance\itemindent\labelsep%
350 \item[\textbf{\exercisename\ \theexercise}]%
351}
352\let\endexercise\endtrivlist
353% \end{macrocode}
354% \end{environment}
355%
356% \subsection{Answers}
357%
358% We need a file in which to store our answers.
359%
360% \begin{macrocode}
361\newwrite\ex@ansfile
362% \end{macrocode}
363%
364% \begin{macro}{\ex@ansfilename}
365%
366% In case anyone has a better idea for a filename than our default, we
367% provide a hook.
368%
369% \begin{macrocode}
370\def\ex@ansfilename{\jobname.ans}
371% \end{macrocode}
372% \end{macro}
373%
374% We open the file at the end of the preamble, to give the user a chance to
375% say |\nofiles|, or change |\ex@ansfilename|.
376%
377% \begin{macrocode}
378\AtBeginDocument{%
379 \if@filesw%
380 \immediate\openout\ex@ansfile=\ex@ansfilename\relax%
381 \answrite\relax%
382 \fi%
383}
384% \end{macrocode}
385%
386% \begin{macro}{\answrite}
387%
388% This writes stuff to the answers file. We make sure that it's
389% appropriately protected, so that you can insert section headings and so on.
390%
391% \begin{macrocode}
392\def\answrite#1{%
393 \if@filesw%
394 \begingroup%
395 \let\protect\@unexpandable@protect%
396 \immediate\write\ex@ansfile{#1}%
397 \endgroup%
398 \fi%
399}
400% \end{macrocode}
401% \end{macro}
402%
403% \begin{macro}{\answer}
404%
405% The |\answer| macro needs to read until the end of the enclosing
406% \env{exercise} environment (or whatever).
407%
408% \begin{macrocode}
409\def\answer{\sv@readenv\ex@answer}
410% \end{macrocode}
411%
412% Now for the main guts.
413%
414% \begin{macrocode}
415\def\ex@answer#1#2{%
416 \begingroup%
417 \@bsphack%
418% \end{macrocode}
419%
420% First of all, check to see whether any counters have changed.
421%
422% \begin{macrocode}
423 \ex@ctrcheck%
424% \end{macrocode}
425%
426% Start a \env{doanswer} environment in the file.
427%
428% \begin{macrocode}
429 \answrite{\noexpand\begin{doanswer}{\theexercise}}%
430% \end{macrocode}
431%
432% Set catcodes to be strange, and read lines one-at-a-time, writing them to
433% the file. When finished, continue at |\ex@endanswer|.
434%
435% \begin{macrocode}
436 \let\do\@makeother\dospecials%
437 \sv@safespc%
438 \sv@read{#1}\answrite{\ex@endanswer#2}%
439}
440% \end{macrocode}
441%
442% When that's done, we wind up here.
443%
444% \begin{macrocode}
445\def\ex@endanswer{%
446 \@esphack%
447 \answrite{\noexpand\end{doanswer}}%
448 \endgroup%
449}
450% \end{macrocode}
451% \end{macro}
452%
db127fce 453% \begin{macro}{\skipanswer}
454%
455% This is much simpler.
456%
457% \begin{macrocode}
458\let\skipanswer\ignore
459% \end{macrocode}
460% \end{macro}
461%
86f6a31e 462% \begin{macro}{\answers}
463%
464% The |\answers| macro closes the file, makes sure that future
465% \env{exercise}s with answers cause an error, and reads in the file.
466%
467% \begin{macrocode}
468\def\answers{%
db127fce 469 \@ifnextchar[{\answers@i\input}{\answers@i\@input[\ex@ansfilename]}%
470}
471\def\answers@i#1[#2]{%
86f6a31e 472 \immediate\closeout\ex@ansfile%
473 \global\let\answrite\exerr@toolate%
db127fce 474 \ex@withext{#1}{#2}{ans}%
475}
476\def\q@delim{\q@delim}
477\def\ex@withext#1#2#3{%
478 \edef\next@##1{\noexpand\ex@ext@i{##1}{#2}{#3}#2.\noexpand\q@delim}%
479 \next@{#1}%
480}
481\def\ex@ext@i#1#2#3#4.#5\q@delim{%
482 \ifx\q@delim#5\q@delim\def\next@{#1{#2.#3}}%
483 \else\def\next@{#1{#2}}\fi%
484 \next@%
86f6a31e 485}
486% \end{macrocode}
487% \end{macro}
488%
489% \begin{environment}{doanswer}
490%
491% A very simple environment. We set the exercise number in bold and then
492% just write the text.
493%
494% \begin{macrocode}
495\def\doanswer#1{%
496 \exfix%
497 \trivlist\advance\itemindent\labelsep%
498 \item[\textbf{#1}]%
499}
500\let\enddoanswer\endtrivlist
501% \end{macrocode}
502% \end{environment}
503%
504% \subsection{Lists inside paragraphs}
505%
506% \begin{environment}{parlist}
507%
508% The \env{parlist} environment is a trimmed-down version of a normal list.
509% We todge the |\item| command, make |\list| and |\trivlist| make errors, and
e8e9e5d8 510% do various normal list things.
86f6a31e 511%
512% \begin{macrocode}
513\def\parlist#1#2{%
514 \let\@trivlist\exerr@parlist%
515 \def\@itemlabel{#1}%
516 \let\makelabel\relax%
517 \@nmbrlistfalse%
518 #2%
519 \let\item\pl@item%
520 \ignorespaces%
521}
522% \end{macrocode}
523% \end{environment}
524%
525% \begin{macro}{\pl@item}
526%
527% This is the implementation of |\item| within a \env{parlist}. The main
528% interesting point is the game with boxes, which has the objective of
529% extracting the text of the item, together with any style changes set by
530% |\makelabel|, but without any stupid bits of glue, or |\llap| or anything
531% like that.
532%
533% \begin{macrocode}
534\def\pl@item{\@ifnextchar[\pl@item@i{\pl@item@i[\@itemlabel]}}
535\def\pl@item@i[#1]{%
536 \if@nmbrlist\refstepcounter{\@listctr}\fi%
537 \setbox\z@\hbox{\makelabel{\global\setbox\@ne\hbox{#1}}}%
538 \ifvmode\leavevmode\else\unskip\hskip1em\fi\box\@ne~\ignorespaces%
539}
540% \end{macrocode}
541% \end{macro}
542%
543% \begin{macro}{\useparlist}
544%
545% We just set the \env{list} environment to use \env{parlist}.
546%
547% \begin{macrocode}
548\def\useparlist{\let\list\parlist\let\endlist\relax}
549% \end{macrocode}
550% \end{macro}
551%
552% \begin{environment}{parenum}
553%
554% Very simple, this. Note that we don't run |\endenumerate|, because that's
555% |\let| to |\endlist|.
556%
557% \begin{macrocode}
558\def\parenum{\useparlist\enumerate}
559\let\endparenum\endparlist
560% \end{macrocode}
561% \end{environment}
562%
563% \subsection{Errors}
564%
565% \begin{macrocode}
566\def\exerr@toolate{%
567 \PackageError{exercise}{Too late now for \string\answrite}{%
568 You can't write answers after you've read the file in. I've^^J%
569 ignored the text you attempted to write. This is why answers^^J%
570 go at the end of a book!%
571 }%
572}
573\def\exerr@parlist{%
574 \PackageError{exercise}{You can't nest a `list' inside a `parlist'.}{%
575 I've found a `list' or `trivlist' environment nested inside^^J%
db127fce 576 a `parlist'. This isn't allowed. You're probably doomed now.%
86f6a31e 577 }%
578}
579%</package>
580% \end{macrocode}
581%
582% Done.
583%
584% \hfill Mark Wooding, \today
585%
586% \Finale
587%
588\endinput