% \let\ifBigTeX=\iffalse ^^A Change this in the obvious fashion if an % ^^A enlarged (>75k maxmem) version of TeX is available % \changes{v2.7}{89/10/16}{Conditional compilation for variant % \protect\TeX's} % \def\fileversion{v2.7} \def\filedate{16 Oct 89} % \DoNotIndex{\@input,\@ixpt,\@listi,\@ne,\@setsize,\@starttoc,\@writefile} % \DoNotIndex{\abovedisplayshortskip,\abovedisplayskip,\advance} % \DoNotIndex{\afterassignment,\begin,\belowdisplayshortskip} % \DoNotIndex{\belowdisplayskip,\bf,\bgroup,\centerline,\closeout,\csname} % \DoNotIndex{\def,\edef,\egroup,\else,\end,\endcsname,\endgraf,\endlist} % \DoNotIndex{\errhelp,\errmessage,\expandafter,\fi,\filedate,\fileversion} % \DoNotIndex{\hbox,\hspace,\hss,\if,\iffalse,\ifnum,\ifx,\ignorespaces} % \DoNotIndex{\immediate,\input,\item,\itemsep,\ixpt,\jobname,\labelsep} % \DoNotIndex{\labelwidth,\leavevmode,\leftmargin,\let,\line,\list,\loop} % \DoNotIndex{\lowercase,\m@ne,\makebox,\makelabel,\meaning,\newcount} % \DoNotIndex{\next,\noexpand,\openout,\parsep,\put} % \DoNotIndex{\relax,\repeat,\rm,\romannumeral,\rule,\sloppy,\space,\string} % \DoNotIndex{\strut,\tensf,\the,\tiny,\topsep,\typein,\typeout,\unitlength} % \DoNotIndex{\uppercase,\vtop,\z@} % % \changes{v2.1}{89/04/27}{Total revision of documentation part} % \changes{v2.3}{89/05/17}{Used raw \protect\TeX\protect\space counters} % \changes{v2.5}{89/09/01}{Final revisions for publication} % \changes{v2.6}{89/10/13}{Consistent indentation of {\tt\protect\bslash % def}s} % % \title{Some Macros to Draw Crosswords\thanks{This file is \fileversion, % dated \filedate}} % \author{B Hamilton Kelly\thanks{Especial thanks to my colleague Niel % Kempson for many helpful suggestions, and to Frank Mittelbach of the % Johannes Gutenberg University of Mainz, who saved me two pages of code!}} % \maketitle % \begin{abstract} % The {\sf crossword} environment is intended to be used to typeset % crossword puzzles for use in newsletters, etc. % \end{abstract} % % \vspace*{3pt}\hrule % % % \tableofcontents % % \addtocontents{toc}{\protect\begin{multicols}{2}} % % \listoffigures % % \ifBigTeX % \else % \addtocontents{lof}{\protect\begin{multicols}{2}} % \fi % % \[ \vbox{\hrule width 4cm} \] % % \begin{multicols}{2}[\section{Introduction}] % % As a small diversion from the statistics of computer availability, lists % of new software, and the like, Computer Centre Newsletters often include a % crossword for the amusement of their readers.\footnote{That at RMCS has a % bottle of wine as a prize!} % % The macros presented in this document provide a \LaTeX{} method of % typesetting these, and also assist the composer to ensure that the % ``grid'' all goes together correctly. The grid generated is the more % usual form, with black squares separating the ``lights'' which receive the % answers to the clues. Work is in hand to be able to handle the {\sl % Mephisto/Azed\/} type of grid, in which only thicker grid lines % separate the lights. % % A sample crossword appears as Figure~\ref{crossword:1}; I've left the % grid blank for those who want some intellectual exercise: those who don't % can cheat by reading the source listing at the end of this % article! % % % \DescribeEnv{crossword} % The whole crossword, including the \verb+\clue+ commands ({\it q.v}.), % is bracketed within the {\sf crossword} environment. This requires that % the user specifies two parameters:\begin{description} % \item[\meta{gridsize}] This is a number which specifies the columns % (and rows) in the square grid. % \item[\meta{visible}] This controls whether the answers are to be % ``filled in''; obviously of no use for publication, but useful whilst % composing the crossword. If the parameter provided is the letter `{\tt % Y}', then the answers will be typeset; if `{\tt N}' then the lights % will be left blank. Any other value\footnote{The lower-case letters % `{\tt y}' and `{\tt n}' are also recognized} provided for this % parameter will cause \LaTeX{} to input a yes/no answer by interaction % with the user. % \end{description} % % \DescribeEnv{crossword*} % An analogous environment is provided especially for typesetting a smaller % version of a grid showing, for example, ``Last Month's Solution''. In % this of course, the answers {\em always\/} appear, and the clues are not % printed. Again it takes two parameters: % \begin{description} % \item[\meta{gridsize}] As before, this specifies the number of squares % in each axis. % \item[\meta{header\_text}] Some text which will be set (in {\bf bold}) % above the completed grid. % \end{description} % \ifBigTeX % \changes{v2.5a}{89/09/08}{Put the {\protect\sf crossword*} in-line} % \changes{v2.7}{89/10/16}{Conditional compilation for variant % \protect\TeX's} % Here is an example of the {\sf crossword*} % environment: % % \begin{crossword*}{15}{Last month's solution} % \input{grid_0} % \end{crossword*} % \else % Figure~\ref{crossword:2} shows an example of the {\sf crossword*} % environment. % \fi % % \DescribeMacro\clue % Within the body of these environments appear a succession of \verb+\clue+ % commands; each of these takes a total of seven (!) parameters: % \begin{description} % \item[\meta{clue\_number}] The number of the light on the grid, for % example \verb+{17}+. See~\ref{clue-numbers} below for details of how % more complex specifications may be given for multiple lights. % \item[\meta{Across/Down}] This parameter {\em must\/} be either the % letter `{\tt A}' or `{\tt D}', in upper-case. % \item[\meta{col\_number}] The $x$-coordinate of the first square of the % light. The left-most column of the grid is numbered 1. % \item[\meta{row\_number}] The $y$-coordinate of the first square of the % light. The top-most row is numbered 1. % \item[\meta{answer}] The answer to the clue (or that part of it which % appears in the light numbered \meta{clue\_number}). This must be a % string of upper-case letters {\em only\/}; no spaces, punctuation, % hyphens, etc. % \item[\meta{text}] The text of the clue itself. If you want to use any % \LaTeX{} macros in this text, such as \verb+\dots+, each such macro must % be preceded by \verb+\noexpand+. This includes such macros as \verb+\&+, % to produce an explicit ampersand. % \item[\meta{help}] Anything to appear after the text, in parentheses; % this will most usually be used for giving the length of the answer, such % as ``7'' or ``2,6,3-3''. Also used when the text of the clue is % associated with another light when this parameter may say something like % ``see 14d''. % \end{description} % % \subsection{How to Specify Clue Numbers}\label{clue-numbers} % % Sometimes the solution to one clue is split amongst a number of % ``lights''. To cover this eventuality, provide a \verb+\clue+ for {\em % each\/} of the lights involved, with the solution to that light {\em % alone\/} given as \meta{answer}. All except the \verb+\clue+ % corresponding to the first light of the solution should have a null % \meta{text}, and the \meta{help} parameter should be something like % ``see 7d''. % % \changes{v2.4}{89/08/15}{Support for empty help field} % If this final parameter is totally empty, no corresponding clue number % is printed: this facility would be used when the current clue is the % next consecutive light, when it is usual to omit any further reference % to the clue number. % % The \verb+\clue+ for the first light of the solution % should provide the {\em entire\/} clue as its \meta{text}, and the % \meta{help} should say something like ``7,3-3''. The \meta{clue\_number} % field should consist of the number of that light, followed immediately % by the text required to describe the other lights, separated from it by % some non-digit character, for example, a space. % % % \end{multicols} % % \begin{figure*}[tp] % \begin{crossword}{15}{N} % \input{grid_1} % \end{crossword} % \caption{A Sample Crossword}\label{crossword:1} % \end{figure*} % % For example, suppose the clue ``Bill's desired outcome?'', has the % solution `ACT OF PARLIAMENT' which is to go into lights 9d and 13a. % Then\footnote{note the {\tt\string\noexpand} before the {\tt\string\rm} % for the {\tt\string\&}} % \begin{verbatim} % \clue{13}{A}{5}{1}{PARLIAMENT}{}{see 9d} % \clue{9 {\noexpand\rm\&} 13a}{D}{1}{10}{ACTOF}% % {Bill's desired outcome?}{3,2,10} % \end{verbatim} % will produce\begin{description} % \item[13] (see 9d) % \end{description} amongst the ACROSS clues, and\begin{description} % \item[9 {\rm\&} 13a] Bill's desired outcome? (3,2,10) % \end{description} amongst the DOWN % clues % % \ifBigTeX % \else % \begin{figure}[hbtp] % \begin{crossword*}{15}{Last month's solution} % \input{grid_0} % \end{crossword*} % \caption{An example of the {\sf crossword*} % environment}\label{crossword:2} % \end{figure} % \fi % % \StopEventually{\printindex % \PrintChanges % \ifBigTeX % \else % \addtocontents{lof}{\protect\end{multicols}}% % \fi % \addtocontents{toc}{\protect\end{multicols}}} % % \section{Definition of the Macros} % % As always, we start by identifying this version of the style file. % % \begin{macrocode} \typeout{Style option: `crossword' \fileversion\space\space <\filedate> (BHK)} % \end{macrocode} % % \begin{macro}{\ninept} % \begin{macro}{\@listi} % We define a new font size to ensure clues are set at 9pt, no matter what % style size option is in effect. This command also defines suitable % parameters for list environments set in this size of type. % % \begin{macrocode} \def\ninept{\@setsize\ninept{11pt}\ixpt\@ixpt \abovedisplayskip 8.5pt plus 3pt minus 4pt \belowdisplayskip \abovedisplayskip \abovedisplayshortskip \z@ plus2pt \belowdisplayshortskip 4pt plus2pt minus 2pt \def\@listi{\itemsep 0pt \parsep \z@ plus 1pt \topsep 4pt plus 2pt minus 2pt }} % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Counters and Lengths} % \begin{macro}{\ifnumberit} % \begin{macro}{\numberittrue} % \begin{macro}{\numberitfalse} % % The {\sf crossword} environment draws a grid (with black and white % squares); each ``light'' into which a clue's answer is to be written has % to be numbered, and this number will be typeset (using \verb+\tiny+) in % the top-left corner of the first square of the light. % % This style option also provides the {\sf crossword*} environment, which % is intended to be used to produce ``last month's solution'' in a smaller % grid. There is insufficient room for clue numbers to appear on the grid % in this mode, so \verb+\ifnumberit+ is used to indicate whether the % numbers should be set. % % \begin{macrocode} \newif\ifnumberit % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\gr@dsize} % \changes{v2.3}{89/05/17}{Use a raw \protect\TeX\protect\space counter} % \begin{macro}{\p@csize} % \changes{v2.3}{89/05/17}{Use a raw \protect\TeX\protect\space counter} % The counter \verb+\gr@dsize+ is used to hold the width of the grid, as the % number of squares in each direction. % % To prevent too much run-time arithmetic, the counter \verb+\p@csize+ is set % to be one count higher than \verb+\gr@dsize+. % \begin{macrocode} \newcount{\gr@dsize} \newcount{\p@csize} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\Down} % \changes{v2.3}{89/05/17}{Use a raw \protect\TeX\protect\space counter} % \begin{macro}{\Across} % \changes{v2.3}{89/05/17}{Use a raw \protect\TeX\protect\space counter} % As we move around the grid, determining whether squares are black or % white, we utilize the counters \verb+\Across+ and \verb+\Down+ to keep track % of our location. % % \begin{macrocode} \newcount{\Down} \newcount{\Across} % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Reading and Writing the Clues} % % \begin{macro}{\tf@acr} % \begin{macro}{\tf@dwn} % \begin{macro}{\OpenClueFiles} % \changes{v2.1}{89/04/27}{Now uses {\tt\protect\bslash @starttoc}} % \changes{v2.1}{89/04/27}{and {\tt\protect\bslash @writefile}} % Whilst we are determining the appearance of the grid, we copy the text of % each of the clues to an auxiliary file, so that the latter may later be % read back to generate the clues themselves after the grid has been % printed. % % This macro opens a new file, with file extension \verb+.acr+, and puts % into it the commands necessary to typeset the Across clues. It also % opens a \verb+.dwn+ file, which is similarly filled with the Down clues. % % These files are created in the same manner as table-of-contents % ({\tt.toc}) files, etc; thus \LaTeX{} will create file ``handles'' with % names \verb+\tf@acr+ and \verb+\tf@dwn+. However, that would ordinarily % attempt to {\em read\/} the given file first, and also might defer the % actual opening; therefore, we start a new group in which we redefine % \LaTeX's \verb+@input+ command and \TeX's \verb+\openout+ primitive. % % \begin{macrocode} \def\OpenClueFiles{{\let\OpenOut=\openout \def\openout{\immediate\OpenOut}% \let\@input=\@gobble \@starttoc{acr} \@starttoc{dwn}} % \end{macrocode} % Here's the preliminary material that gets inserted into the {\tt.acr} file. % \begin{macrocode} \@writefile{acr}{\string\begin{minipage}[t]{70mm}} \@writefile{acr}{ \string\centerline{\string\bf\ ACROSS}} \@writefile{acr}{ \string\sloppy} \@writefile{acr}{ \string\ninept} \@writefile{acr}{ \string\begin{ClueList}} % \end{macrocode} % Whilst something similar goes into the {\tt.dwn} file. % \begin{macrocode} \@writefile{dwn}{\string\begin{minipage}[t]{70mm}} \@writefile{dwn}{ \string\centerline{\string\bf\ DOWN}} \@writefile{dwn}{ \string\sloppy} \@writefile{dwn}{ \string\ninept} \@writefile{dwn}{ \string\begin{ClueList}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\CloseClueFiles} % \changes{v2.1}{89/04/27}{Now uses {\tt\protect\bslash @writefile}} % After the grid has been printed, we can close the ``clues'' files; these % will later be read back in (by the \verb+\endcrossword+ command) to set % the text of the clues below the grid. % % Before closing, we insert the material that completes the two {\sf % ClueList} environments; firstly across\dots % \begin{macrocode} \def\CloseClueFiles{% \@writefile{acr}{ \string\end{ClueList}} \@writefile{acr}{\string\end{minipage}} % \end{macrocode} % Then for the down clues. % \begin{macrocode} \@writefile{dwn}{ \string\end{ClueList}} \@writefile{dwn}{\string\end{minipage}} % \end{macrocode} % Now we can close those files, and make them ``invisible'' if someone % tries to write to them. % \begin{macrocode} \immediate\closeout\tf@acr \let\tf@acr=\relax \immediate\closeout\tf@dwn \let\tf@dwn=\relax \endgraf } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Tabulating the Clues} % The auxiliary files contain the texts of the clues, each given as an % \verb+\item+ for the {\sf ClueList} environment. This is similar to a % {\sf description} list, except that overlong labels run on into the text % rather than sticking out to the left. % % \begin{macro}{\ClueList} % \begin{macro}{\ClueListLabel} % This sets up the {\sf ClueList} environment, and defines the appearance of % the label. % % \begin{macrocode} \def\ClueListlabel#1{\hspace\labelsep {\bf #1}\hss} \def\ClueList{\list{}{\labelwidth\leftmargin \advance \labelwidth by -\labelsep \let\makelabel\ClueListlabel}} \let\endClueList\endlist % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\PrintClues} % The following macro reads in the two files (of Across and Down clues), % and sets them alongside each other, separated by a vertical rule. Clues % are set in the style of the {\sf ClueList} environment. % % \begin{macrocode} \def\PrintClues{% \centerline{% \begin{tabular}{ c | c } \@input{\jobname.acr} & \@input{\jobname.dwn} \end{tabular} }\endgraf } % \end{macrocode} % \end{macro} % % \section{Creating the Grid} % The remaining commands are concerned with creating (and, optionally, % populating) the crossword grid % % \begin{macro}{\crossword} % % The {\sf crossword} environment takes two parameters: {\em viz}.~the % size of the matrix, and the indication of whether the grid is to include % the answers. (If the latter is omitted, \LaTeX\ will request it % interactively.) % % \begin{macrocode} \def\crossword#1#2{% % \end{macrocode} % % \changes{v2.4}{89/08/15}{Group within \string\crossword\space environment} % \changes{v2.6}{89/10/13}{Removed {\tt\protect\bslash iffalse} hack} % We start off with a \verb+\vtop+ box and a group to hold everything % within the environment, so as to ensure that user-entered text remains % with the crossword. % % \begin{macrocode} \endgraf\leavevmode \vtop\bgroup % \end{macrocode} % % The {\sf crossword} environment uses the full-size grid, and has the % lights numbered. Furthermore it doesn't have any heading to output (see % the {\sf crossword*} environment). % % \begin{macrocode} \unitlength 6mm\numberittrue \def\Header{}% % \end{macrocode} % % We now open the auxiliary files into which the clues are written, and % determine (interactively if necessary) whether the answers are to be % written into the grid. % % \begin{macrocode} \OpenClueFiles \TestAnswers{#2}% % \end{macrocode} % % Finally, we generate the necessary macros to describe the grid as being % entirely filled with black squares; for each square, a macro whose name is % of the form \verb+\RiCi+, \verb+\RxiiCviii+, {\em etc}.\ is created. As % the \verb+\clue+ commands are read in, these will be redefined to produce % the correct appearance when the macros are later expanded. % % \begin{macrocode} \SetUpGrid{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\endcrossword} % % When all the clues have been processed, we can invoke \verb+\FinishGrid+ % to draw the grid. The \verb+\FinishGrid+ and \verb+\PrintClues+ commands % draw the grid and tabulate the clues, respectively. By enclosing them in % a vertical mode list, we ensure that they remain stuck together on one % page! % % The {\sf crossword} environment defines \verb+\Header+ to be empty, but % the user may give it an explicit definition within the environment; if so, % we'll print it just above the grid itself. % % \begin{macrocode} \def\endcrossword{\endgraf \centerline{\Header}% \hbox{\FinishGrid}% % \end{macrocode} % % We can now finish off the auxiliary files and then read them back in to % set the text of the clues below the grid. % % \changes{v2.4}{89/08/15}{Group within \string\crossword\space environment} % \changes{v2.6}{89/10/13}{Removed {\tt\protect\bslash iffalse} hack} % Finally, we complete the group and the \verb+\vtop+ box. % % \begin{macrocode} \CloseClueFiles \hbox{\PrintClues}% \egroup } % \end{macrocode} % \end{macro} % % \begin{macro}{\crossword*} % \changes{v2.6}{89/10/13}{Removed {\tt\protect\bslash iffalse} hack} % \begin{macro}{\endcrossword*} % \changes{v2.1}{89/04/27}{No longer opens {\tt.acr} and {\tt.dwn} files} % \changes{v2.6}{89/10/13}{Removed {\tt\protect\bslash iffalse} hack} % The {\sf crossword*} environment doesn't need a second parameter to % control printing of answers, because it {\bf always} populates the grid % with the answers. Instead, its second parameter provides the text to % appear above the printed grid. Its actions are as for the {\sf % crossword} environment except that\begin{itemize} % \item It prints the descriptive text above the grid. % \item It {\bf always} outputs the answers, without numbers. % \item It draws them in a smaller box. % \item It doesn't output the clues (it doesn't even open any % auxiliary files!) % \end{itemize} % % \begin{macrocode} \expandafter\def\csname crossword*\endcsname#1#2{% \unitlength 4mm\numberitfalse \endgraf\leavevmode \vtop\bgroup \def\Header{{\bf\strut #2}}% \def\answer{Y}% \let\tf@dwn=\relax \let\tf@acr=\relax \SetUpGrid{#1}} \expandafter\def\csname endcrossword*\endcsname{\endgraf \centerline{\Header}% \hbox{\FinishGrid}% \egroup } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Macros used when Populating the Grid} % % \begin{macro}{\laterletter} % \changes{v2.1}{89/04/27}{Used to be {\tt\protect\bslash letterput}} % The following macro calls this to ``place'' the letters of a solution by % defining a macro unique to this square. % % \begin{macrocode} \def\laterletter#1{\setsquare{\lettersquare{#1}}} % \end{macrocode} % % \begin{macro}{\nextletter} % \begin{macro}{\nextlet} % % To determine how much space is required for the light corresponding to % an answer, we need to cycle through each of the characters of the answer % individually; this macro is called with two parameters --- the first % indicates the current setting direction (and thus accesses one of the % counters \verb+\Across+ or \verb+\Down+), whilst the second consists of % the characters forming the answer followed by the string \verb+\@nil+. % When it is called, this ``second'' parameter is {\em not\/} enclosed in % braces, so only the first token in it is accessed. The macro calls % itself recursively to process the remaining characters until the % \verb+\@nil+ has been met. % % \changes{v2.1}{89/04/27}{Can now process {\em first\/} letter of light} % \begin{macrocode} \def\nextletter#1#2{% % \end{macrocode} % % If the next token is \verb+\@nil+, we've finished; the \verb+\let+ ensures % that its parameter will be discarded (through the \LaTeX{} internal % command \verb+\@gobble+) and the recursion will then unravel. % % \changes{v2.1}{89/04/27}{Use \protect\LaTeX's {\tt\protect\bslash @gobble} % command} % \begin{macrocode} \ifx#2\@nil \let\nextlet=\@gobble % \end{macrocode} % % Otherwise, we have another letter of the \meta{answer} in {\tt\#2}, so we % call \verb+\letterput+ to define the macro corresponding to this square, % and count one more position occupied in the current direction. % % \begin{macrocode} \else\letterput{#2}\advance#1 by \@ne % \end{macrocode} % % After we've processed this letter, we want to call this routine % recursively to process the remaining letters (if any)\dots % % \changes{v2.1}{89/04/27}{Change to handle subsequent letters of light} % \begin{macrocode} \let\nextlet=\nextletter % \end{macrocode} % % These letters cannot possibly require a starting square number, so we % use a simpler macro for these later letters. % % \begin{macrocode} \let\letterput=\laterletter \fi % \end{macrocode} % % This is where we either exit from the recursion (and \verb+\@gobble+ the % {\tt\#1} parameter) or call the macro recursively to process the next % character; the direction has to be passed on as the first parameter for % \verb+\nextletter+ or \verb+\@gobble+. % % \begin{macrocode} \nextlet{#1}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\blacktest} % Later we shall want to check that the square into which we are ``putting'' % a letter is either black (and hence should be changed to contain the % character) or has already had the {\em same\/} letter put into it by an % intersecting light. % % We don't want to expand each squares' macros, so these tests have to use % the \verb+\ifx+ primitive; therefore, we need a macro which has the same % substitution text {\em at the highest level}. % % \begin{macrocode} \def\blacktest{\blacksquare} % \end{macrocode} % \end{macro} % % \begin{macro}{\ifneed@d} % \begin{macro}{\need@dtrue} % \begin{macro}{\need@dfalse} % As we create the macros corresponding to each occupied square, we have to % decide whether it is necessary to actually perform a (re)definition of the % macro; the following permits the code to determine whether such definition % takes place (within the \verb+\putsquare+ macro). % % \begin{macrocode} \newif\ifneed@d % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\ifNoerr} % \begin{macro}{\Noerrtrue} % \begin{macro}{\Noerrfalse} % If an error is detected during the placement of the occupied squares, % there will probably be other errors; to save pouring out yards of error % messages, we arrange to suppress all but the first such; the following % \verb+\newif+ provides this facility. % % And of course we start without any errors! % % \begin{macrocode} \newif\ifNoerr \Noerrtrue % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\Number} % \begin{macro}{\Plain} % To determine whether a square has already been occupied, and if so, by % what, we require a couple of new tokens which can be tested for as the % result of a macro expansion % \begin{macrocode} \newtoks\Number \newtoks\Plain % \end{macrocode} % % \begin{macro}{\blank} % \begin{macro}{\numbered} % The next two definitions can be temporarily \verb+\let+ to be the % replacements for \verb+\lettersquare+ and \verb+\numbersquare+ % respectively, for use in conjunction with the aforementioned test. % % \begin{macrocode} \def\blank#1{\Plain} \def\numbered#1#2{\Number} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\letterinsquare} % \begin{macro}{\letterinnumbersquare} % When we first read the clues, we create macros which are unique to each % square; later we shall redefine the macros to which the squares' macros % expand to actually perform the setting, but during the first phase we % require expansions which correspond to the parameters alone. The % following definitions are therefore used during the ``filling'' phase. % % \begin{macrocode} \def\letterinsquare#1{#1} \def\letterinnumbersquare#1#2{#2} % \end{macrocode} % % \begin{macro}{\setsquare} % As we scan the answers for each clue, this macro is called with a % parameter which specifies a call of either the \verb+\lettersquare+ or % \verb+\numbersquare+ macros (with appropriate parameters). % % It starts by assuming that no redefinition of the square's macro will be % required. % % \begin{macrocode} \def\setsquare#1{% \need@dfalse % \end{macrocode} % % This macro is also called during the initialization of the grid, when we % populate it with black squares; therefore, we definitely want to perform a % definition of the square's macro at this stage. % % \begin{macrocode} \ifx#1\blacksquare \need@dtrue % \end{macrocode} % % Otherwise, let's have a look and see what is already in the square's % macro. This test will succeed only if the square contains its initial % definition (as \verb+\blacksquare+). % \begin{macrocode} \else \expandafter\ifx\csname\ther@w\thec@l\endcsname\blacktest % \end{macrocode} % % in which case we {\em will\/} want to redefine the macro for this square % % \begin{macrocode} \need@dtrue % \end{macrocode} % % If the square has already been redefined, it means we've already ``put'' a % letter (or number+letter) into its definition, so we will have to check % that this definition doesn't conflict with the new one (which is in % {\tt\#1}). We have to expand the macros to perform this test, but don't % want that expansion to return anything except the letter which is being % (and has been) placed in the square, so we make a temporary replacement % for the two macros which might form our {\tt\#1}. % \begin{macrocode} \else \let\lettersquare=\letterinsquare \let\numbersquare=\letterinnumbersquare % \end{macrocode} % % Now we {\em expand\/} the original definition and the new one; these % should be the same! % \changes{v2.6}{89/10/13}{Minor revision of layout} % % \begin{macrocode} \expandafter\if\csname\ther@w\thec@l\endcsname#1 \else % \end{macrocode} % % If they aren't, it means the compiler of the crossword has made a mistake % and has solutions which don't correctly intersect: tell him so (well, the % first time anyway). We even provide the user with some help! % % \begin{macrocode} \ifNoerr \errhelp{Two intersecting lights tried to put different letters^^Jin the same square! You've probably confused their coordinates.^^J Carry on, and examine the printout.} \errmessage{Illegal redefinition of square \ther@w\thec@l. Was: \expandafter\meaning\csname\ther@w \thec@l\endcsname. Now: \noexpand #1} \Noerrfalse \fi \fi % \end{macrocode} % % So far, we don't seem to need to change anything, but if the new {\tt\#1} % which has been passed to \verb+\putsquare+ specifies that it be numbered, % we must subsume any existing definition which {\em doesn't\/} have a % number. % % Again, we make temporary reassignments for the two potential macros, which % is where we make use of the two new tokens that we invented. % % \begin{macrocode} \let\lettersquare=\blank \let\numbersquare=\numbered % \end{macrocode} % % If the following test succeeds, we know that the new parameter specifies a % number as well as a letter. This code could be expanded to check whether % the original definition also specified a number, and if so ensure that % they are the same, but would anybody really be silly enough to give % different numbers for clues starting from the same square?! % \begin{macrocode} \expandafter\ifx#1\Number \need@dtrue \fi \fi \fi % \end{macrocode} % % Now we know whether we must (re)define the macro which is unique to this % square. If we must, we expand our {\tt\#1}, so as to get the actual % number and letter passed in through that parameter, but keep the name of % the placement macro itself\footnote{This will be the first token of the % parameter itself.} unexpanded. % % \begin{macrocode} \ifneed@d \expandafter\edef\csname\ther@w\thec@l\endcsname{\noexpand #1} \fi } % \end{macrocode} % \end{macro} ^^A \setsquare % \end{macro} ^^A \letterinnumbersquare % \end{macro} ^^A \letterinsquare % % \subsection{The {\tt\protect\bslash clue} Command} % % \begin{macro}{\clue} % % Well, here it is at last. We start off by extracting the parts (if any) % which form the \meta{clue\_number} parameter. We will therefore have % the purely numeric first portion of the \meta{clue\_number} in % \verb+\cluenumber+. % % \begin{macrocode} \def\clue#1#2#3#4#5#6#7{% \findnumber{#1} % \end{macrocode} % % We now examine the second (\meta{Across/Down}) parameter of the % \verb+\clue+ command to determine whether this is an Across or Down % clue. The clue's \meta{text} and \meta{help} information is then % written\footnote{The writes only take place if the output files exist, % and the \meta{help} parameter is non-empty.} to the appropriate % auxiliary file, and note taken of the direction in which the % \meta{answer} should be set into the light of the grid. % % \changes{v2.4}{89/08/15}{Support for empty help field} % % Firstly we deal with writes to the {\tt.acr} file, if the % \meta{Across/Down} parameter is the letter `{\tt A}'. In this case, the % counter to be incremented is \verb+\Across+. % \begin{macrocode} \ifx#2A \if\@empty#7\relax\else \ifx\tf@acr\relax\else \@writefile{acr}{ \string\item[#1] #6 (#7)}% \fi \fi \let\Direction=\Across \else % \end{macrocode} % If this parameter is the letter `{\tt D}', writes go to the {\tt.dwn} % file, and the \verb+\Down+ counter is incremented. % \begin{macrocode} \ifx#2D \if\@empty#7\relax\else \ifx\tf@dwn\relax\else \@writefile{dwn}{ \string\item[#1] #6 (#7)}% \fi \fi \let\Direction=\Down \else % \end{macrocode} % % If this \meta{Across/Down} parameter is not one of the two permitted % characters, an error message is issued. % % \begin{macrocode} \errhelp{The second parameter of the \string\clue\space command must be `A' or `D'} \errmessage{Illegal direction (#1) specification for \string\clue.} \fi \fi % \end{macrocode} % % The $x$ and $y$ coordinate counters are set from the \meta{column} and % \meta{row} parameters. % % \begin{macrocode} \Across=#3 \Down=#4 % \end{macrocode} % % \begin{macro}{\letterput} % \changes{v2.1}{89/04/27}{Replacement for {\tt\protect\bslash firstletter} % method} % % The \verb+\letterput+ macro is defined anew at the start of each clue to % create the correct definition for the {\em first\/} square of each % light. The \verb+\setsquare+ macro redefines this macro internally for % the remaining squares. % % \begin{macrocode} \edef\letterput##1{\noexpand\setsquare {\noexpand\numbersquare {\noexpand\cluenumber}{##1}}}% % \end{macrocode} % \end{macro} % % Now we can call \verb+\nextletter+ which will cycle through all the % letters of the \meta{answer} until meeting the token \verb+\@nil+. % As each letter is processed, it creates a definition for the current % square, initially using the above definition, and then \verb+\laterletter+ % for subsequent letters of the \meta{answer}. % % Finally, we ensure that the newlines after \verb+\clue+ commands don't % lead to unwanted spaces being typeset. % \changes{v2.6}{89/10/13}{Minor revision of layout} % \begin{macrocode} \nextletter{\Direction}#5\@nil \ignorespaces } % \end{macrocode} % \end{macro} % % \subsubsection{Finding the clue number to be set in the light} % \begin{macro}{\findnumber} % % We mentioned earlier that clues with solutions which occupy more than % one light require a special format for specifying their % \meta{clue\_number}. If this form is required, the number of the current % light is given first, with the remaining text (as it is required to be % set) following, separated from the first number by some non-digit % character. % % The macro \verb+\findnumber+ is called with the entire % \meta{clue\_number} parameter passed to \verb+\clue+ and sets % \verb+\cluenumber+ to expand to the first or only number found in that % parameter (which should then appear in the first square of the light). % % \begin{macro}{\clueNumber} % Of course, we require a counter in which to attempt to assemble that number: % \begin{macrocode} \newcount\clueNumber % \end{macrocode} % % \begin{macro}{\special@gobble} % This macro is used by \verb+\findnumber+ to discard the unwanted portion % (if any) of a \meta{clue\_number}, including the special termination % token. % % \begin{macrocode} \def\special@gobble #1\@nil{} % \end{macrocode} % % The following mechanism to separate the first (or only) number from the % remainder was suggested by Frank Mittelbach of the University of Mainz, % and replaced about two pages worth of code. % \changes{v2.2}{89/05/17}{Much quicker clue number extraction} % \begin{macrocode} \def\findnumber#1{% % \end{macrocode} % We attempt to assign the \meta{clue\_number} parameter to the % \verb+\clueNumber+ counter: only that portion consisting purely of digits % will actually be assigned. The remainder, if any, including the special % terminator sequence \verb+\@nil+ is then discarded by the % \verb+\special@gobble+ command: % % \begin{macrocode} \afterassignment \special@gobble \clueNumber=0#1 \@nil % \end{macrocode} % % \changes{v2.6}{89/10/13}{Minor revision of layout} % If the user did not provide a valid \meta{clue\_number} (i.e.\ something % starting with a digit), then \verb+clueNumber+ will have zero assigned to % it --- seems the user ought to be told about this! % % This completes \verb+\findnumber+. % % \begin{macrocode} \ifnum\clueNumber=0 \errhelp{The first parameter of the \string\clue\space command must commence with a digit} \errmessage{Illegal clue number (#1) specified for \string\clue.} \fi } % \end{macrocode} % \end{macro} ^^A \special@gobble % \end{macro} ^^A \clueNumber % \end{macro} ^^A \findnumber % % \begin{macro}{\cluenumber} % This macro merely produces the number as saved in \verb+\clueNumber+. % \begin{macrocode} \def\cluenumber{\the\clueNumber} % \end{macrocode} % \end{macro} ^^A \cluenumber % % \subsection{Populating the Crossword Grid} % \begin{macro}{\blackenrow} % \changes{v2.2}{89/05/17}{Used {\tt\protect\bslash blackenrow} for inner loop} % For each column in a row we create a black square; effectively % \verb+\setsquare+ will execute the definition % \begin{macrocode} % \def\csname\ther@w\thec@l\endcsname{\blacksquare} % \end{macrocode} % so that for row~3 column~6 of a $15\times15$ grid, for example, we would % end up by defining \verb+\def\RiiiCvi{\blacksquare}+. % % Before starting the inner loop, we need to save the definition of % \verb+\body+ which was created for the outer loop. We cannot do this by % creating a new block, since that would require that each square be defined % globally, which might give rise to save stack overflow problems. % % \begin{macrocode} \def\blackenrow{\let\savedbody=\body \loop\relax\ifnum\Across>\z@ \setsquare{\blacksquare}% % \end{macrocode} % % We then shift ourselves back to the next column to the left and iterate. % If we've reached the end of this inner loop, we re-establish the % definition of \verb+\body+. % % \begin{macrocode} \advance\Across by \m@ne \repeat \let\body=\savedbody } % \end{macrocode} % % \begin{macro}{\SetUpGrid} % % This macro creates an empty grid of the appropriate size. % % \begin{macrocode} \def\SetUpGrid#1{% % \end{macrocode} % % We firstly make a note of the \meta{gridsize} parameter in the % \verb+\gr@dsize+ counter, from which the width and height of the grid % may be computed. We also set the \verb+\p@csize+ counter to be one % greater than \verb+\gr@dsize+ to save our recomputing this quantity many % times over. % % \begin{macrocode} \gr@dsize=#1 \p@csize=#1 \advance\p@csize by \@ne % \end{macrocode} % % Right, this is where we start to generate the grid itself. We start at % the bottom edge, because \TeX\ loops are easiest if counting down to % zero. Therefore, the \verb+\Down+ counter is set equal to the highest row % number attainable. % % \begin{macrocode} \Down=\gr@dsize % \end{macrocode} % % We now start a loop, so the following code will be repeated for each row % of the grid in turn. As with the rows, we process the columns from % highest address to lowest, so the \verb+\Across+ counter is also set to the % highest column attainable. % % \begin{macrocode} \loop \Across=\gr@dsize % \end{macrocode} % % Provided we haven't decremented down to the 0th row, we start off the % inner loop to process each column: this is done by invoking a separate % macro --- the alternative to which would be to enclose the inner loop in % a group, which would require the use of global definitions for each % square. % \changes{v2.2}{89/05/17}{Used {\tt\protect\bslash blackenrow} for inner loop} % % \begin{macrocode} \ifnum\Down>\z@ \blackenrow % \end{macrocode} % % % Afterwards we move ourselves up one row, and iterate for the next row. % % % \begin{macrocode} \advance\Down by \m@ne \repeat } % \end{macrocode} % \changes{v2.6}{89/10/13}{Minor revision of layout} % And that's the end of \verb+\SetUpGrid+! % \end{macro} ^^A \SetUpGrid % \end{macro} ^^A \blackenrow % % \begin{macro}{\thec@l} % \begin{macro}{\ther@w} % \verb+\thec@l+ and \verb+\ther@w+ macros generate a string of letters, % starting with `{\tt C}' (for column) and `{\tt R}' (for row) respectively. % The remainder of the string consists of the lower-case Roman numeral % equivalent to the current value of the appropriate counter. Such % all-letter strings are used to create the names for macros which can be % unique for each square of the grid. % % \begin{macrocode} \def\thec@l{C\romannumeral\Across} \def\ther@w{R\romannumeral\Down} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\TestAnswers} % This macro interacts with the user, if necessary, to get a yes or no % indication of whether the answers shall be written into the grid. No % check is made that the user has entered a valid response, but the use of % \verb+\answer+ is such that any answer apart from a `{\tt y}' (in upper- % or lower-case) is treated as if it were `{\tt n}'. % % \begin{macro}{\f@rst} % To determine what parameter has been provided, or the response elicited, % we will require a little macro to pass on the first token of a list % terminated by a full stop. % % \begin{macrocode} \def\f@rst#1#2.{#1} % \end{macrocode} % % We commence by lower-casing the given parameter, setting the lower-cased % version into the macro \verb+\answer+. % \begin{macrocode} \def\TestAnswers#1{\edef\next{\def\noexpand\answer{#1}}% \lowercase\expandafter{\next}% % \end{macrocode} % We can then extract just the first character % \begin{macrocode} \edef\answer{\expandafter \f@rst \answer .}% % \end{macrocode} % The we determine whether it's the letter `{\tt y}' or `{\tt n}'\dots % \begin{macrocode} \if\answer y \else \if\answer n \else % \end{macrocode} % If the \meta{visible} parameter isn't either of these, we ask the user % to give us an answer! % \begin{macrocode} \typein[\answer]{Make answers visible? [Y/N]: }\fi \fi % \end{macrocode} % OK, \verb+\answer+ now contains some response; let's upper-case it and % extract just its first character % \begin{macrocode} \edef\next{\def\noexpand\answer{\answer}}% \uppercase\expandafter{\next}% \edef\answer{\expandafter \f@rst \answer .}% } % \end{macrocode} % \end{macro} % \end{macro} % % % \subsection{Setting the Grid} % % \begin{macro}{\letter} % This is the expansion which is used (for \verb+\letterinsquare+, % and within the expansion of \verb+\numberedsquare+) when the grid is % actually being {\em typeset\/} from the stored squares' macros. % % \begin{macrocode} \def\letter#1{{\put(\Across,-\Down){\makebox(1,1){\tensf #1}}}} % \end{macrocode} % % \begin{macro}{\numberedsquare} % This macro is used (for \verb+\numbersquare+) when the lights are being % drawn with light numbering enabled. It puts the number (and the letter of % the answer too, depending upon the definition of \verb+\letter+ which is % current) at the current coordinate position specified by % \verb+(\Across,\Down)+. % \begin{macrocode} \def\numberedsquare#1#2{% \put(\Across,-\Down){% % \end{macrocode} % % To insert the clue number, we generate it within a sub-picture, of size % equal to one square. % % \begin{macrocode} \begin{picture}(1,1)(0,0) % \end{macrocode} % % We stick the number in the top-left corner of an (invisible) box which % fills the central 81\% of the area. % % \begin{macrocode} \put(0.05,0.05){\makebox(0.9,0.9)[tl]{\tiny #1}} \end{picture}% } % \end{macrocode} % % We also set the letter in the square (depending upon the definition of % \verb+\letter+ which applies. % % \begin{macrocode} \letter{#2}} % \end{macrocode} % % \begin{macro}{\unnumberedsquare} % Despite its name, this macro is invoked (through \verb+\numbersquare+) for % those squares which would ordinarily carry a light's number, were it not % for the fact that the numbers have been suppressed by the {\sf crossword*} % environment. % % It just discards the \meta{clue\_number} given in the first parameter and % sets the current letter by invoking \verb+\letter+, which uses the second % parameter\dots % % \begin{macrocode} \def\unnumberedsquare#1{\letter} % \end{macrocode} % \end{macro} ^^A \unnumberedsquare % \end{macro} ^^A \numberedsquare % \end{macro} ^^A \letter % % \begin{macro}{\FinishGrid} % Now we can process all the stored macros which define the appearance of % each square in the grid, and thus generate the printed version thereof, % using \LaTeX's {\sf picture} environment. % % This command makes appropriate redefinitions of some macros which produced % different effects during the filling of the grid. % \changes{v2.2}{89/05/17}{Removed extraneous opening space after brace} % \changes{v2.6}{89/10/13}{Minor revision of layout} % \begin{macrocode} \def\FinishGrid{% % \end{macrocode} % % If the customer doesn't want the letters put into the grid, then we % need only throw away any parameter to \verb+letter+. % % \begin{macrocode} \if\answer Y \else \let \letter=\@gobble \fi % \end{macrocode} % % As stated in the introduction, when typesetting the grid in a smaller % version, there is insufficient space to include the numbers for the % lights; by testing \verb+\ifnumberit+ we can determine whether a macro % which expands to \verb+\numbersquare+ shall result in a number being % printed or not. % % \begin{macrocode} \ifnumberit \let\numbersquare=\numberedsquare \else \let\numbersquare=\unnumberedsquare \fi % \end{macrocode} % % Anything that's been stored as a \verb+\lettersquare+ is ``set'' using the % \verb+\letter+ macro (which we might have just \verb+\let+ equal to % \verb+\@gobble+). % % \begin{macrocode} \let\lettersquare=\letter % \end{macrocode} % % \begin{macro}{\blacksquare} % Any black squares that are still left in the grid are set by means of this % command: % % \begin{macrocode} \def\blacksquare{% % \end{macrocode} % % The black square itself is merely a rule of the appropriate dimensions. % % \begin{macrocode} \put(\Across,-\Down){\rule{\unitlength}{\unitlength}}} % \end{macrocode} % \end{macro} % % % Now we come to the actual body of \verb+\FinishGrid+. % % \changes{v2.6}{89/10/13}{Minor revision of layout} % We start off at the bottom-most row of the grid\dots % % \begin{macrocode} \Down=\gr@dsize % \end{macrocode} % % The whole grid is created in a centered \verb+\hbox+ in a {\sf picture} % environment. By offsetting the origin negatively, we can address each % row by simply negating the $y$ coordinate; thus column $x$ in the highest % row is $(x,-1)$. % % \begin{macrocode} \centerline{% \begin{picture}(\p@csize,\p@csize)(1,-\p@csize) % \end{macrocode} % % We now cycle through each of the rows. The first thing we output is a % horizontal rule of the full width of the grid, one such rule being % generated for each row of the grid, providing the horizontal lines across % vertical lights. % % \begin{macrocode} \loop\ifnum\Down>\z@ \put(1,-\Down){\line(1,0){\the\gr@dsize}} % \end{macrocode} % % Now we are about to cycle across all the columns of the current row; % again, it's convenient for us to work backwards to the left\dots % % \begin{macrocode} \Across=\gr@dsize % \end{macrocode} % % To do this we need an inner loop; this has to be inside a group so as to % isolate the effects of its \verb+\repeat+ command. % % \begin{macrocode} {\loop \ifnum\Across>\z@ % \end{macrocode} % % To set the appropriate object in this square, we merely invoke the macro % which has been associated with the square. Thus we'll end up with a black % square, or a numbered or plain square, the latter two of which may also % contain a letter. % % \begin{macrocode} \csname\ther@w\thec@l\endcsname % \end{macrocode} % % Now we advance to the next column and iterate. That's the end of the % inner loop for each of the columns of the current row. % % \begin{macrocode} \advance\Across by \m@ne \repeat }% % \end{macrocode} % % Now we can decrement down to the next row and iterate through the % rows. % % \begin{macrocode} \advance\Down by \m@ne \repeat % \end{macrocode} % % We've so far drawn a horizontal line {\em under\/} each of the rows; the % next \verb+\put+ draws a final line {\em above\/} the top-most row. % % \begin{macrocode} \put(1,0){\line(1,0){\the\gr@dsize}} % \end{macrocode} % % Similarly, a short loop can draw vertical rules at the left-hand edge of % each of the columns, starting with a line on the left of an imaginary % column to the right of the whole grid, which will therefore form a line to % the right of the final column. % % \begin{macrocode} \Across=\p@csize \loop\ifnum\Across>\z@ \put(\Across,0){\line(0,-1){\the\gr@dsize}} \advance\Across by \m@ne \repeat % \end{macrocode} % % And that completes the picture. % % \begin{macrocode} \end{picture}% }% } % \end{macrocode} % \end{macro} % % Finally, here's the input which produced the crossword in % figure~\ref{crossword:1} % % \begin{macrocode} % \begin{crossword}{15}{N} % \input{grid_1} % \end{crossword} % \end{macrocode} % % where the file \verb+grid_1.tex+ reads as follows: % \IndexListing{grid_1.tex} % % \Finale %