Fix dates and version numbers in the package files.
[mdwtools] / exercise.dtx
1 % \begin{meta-comment} <general public licence>
2 %%
3 %% exercise package -- useful macros for setting exercises with answers
4 %% Copyright (c) 2001--2003 Mark Wooding
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.
10 %%
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.
15 %%
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}
24 %<+package> [2020/09/06 1.14.0 Exercies with answers]
25 % \end{meta-comment}
26 %
27 % \CheckSum{271}
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
51 \errorcontextlines\maxdimen
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 %
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 %
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 %
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 %
207 % \implementation
208 %
209 %
210 %^^A-------------------------------------------------------------------------
211 % \section{Implementation}
212 %
213 % \begin{macrocode}
214 %<*package>
215 % \end{macrocode}
216 %
217 % \subsection{Initialization}
218 %
219 % The \textsf{within} option is handled by the \package{mdwkey} package.
220 %
221 % \begin{macrocode}
222 \RequirePackage{mdwkey}
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
232 \mkdef{exercise:opts}{within}{%
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 %
245 % The |\ex@opts| macro just runs the \package{mdwkey} kit to parse an option
246 % string.
247 %
248 % \begin{macrocode}
249 \def\ex@opts{\mkparse{exercise:opts}}
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 %
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 %
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{%
469 \@ifnextchar[{\answers@i\input}{\answers@i\@input[\ex@ansfilename]}%
470 }
471 \def\answers@i#1[#2]{%
472 \immediate\closeout\ex@ansfile%
473 \global\let\answrite\exerr@toolate%
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@%
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
510 % do various normal list things.
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%
576 a `parlist'. This isn't allowed. You're probably doomed now.%
577 }%
578 }
579 %</package>
580 % \end{macrocode}
581 %
582 % Done.
583 %
584 % \hfill Mark Wooding, \today
585 %
586 % \Finale
587 %
588 \endinput