diff options
Diffstat (limited to 'texmf-dist/source/latex')
-rw-r--r-- | texmf-dist/source/latex/dps/dps.dtx | 3547 | ||||
-rw-r--r-- | texmf-dist/source/latex/dps/dps.ins | 126 |
2 files changed, 2680 insertions, 993 deletions
diff --git a/texmf-dist/source/latex/dps/dps.dtx b/texmf-dist/source/latex/dps/dps.dtx index f4190df9..fc7040ee 100644 --- a/texmf-dist/source/latex/dps/dps.dtx +++ b/texmf-dist/source/latex/dps/dps.dtx @@ -1,932 +1,2615 @@ -% \iffalse
-%<*copyright>
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% dps.sty package, 2006-10-06 %%
-%% Copyright (C) 2006 D. P. Story %%
-%% dpstory@acrotex.net %%
-%% storyd@owc.edu %%
-%% %%
-%% This program can redistributed and/or modified under %%
-%% the terms of the LaTeX Project Public License %%
-%% Distributed from CTAN archives in directory %%
-%% macros/latex/base/lppl.txt; either version 1 of the %%
-%% License, or (at your option) any later version. %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%</copyright>
-%<package>\NeedsTeXFormat{LaTeX2e}
-%<package>\ProvidesPackage{dps}
-%<package> [2006/10/31 v1.0 Das Puzzle Spiel (dps)]
-%<*driver>
-\documentclass{ltxdoc}
-\usepackage[colorlinks,hyperindex]{hyperref}
-\pdfstringdefDisableCommands{\let\\\textbackslash}%
-\EnableCrossrefs \CodelineIndex
-%\OnlyDescription % comment out for implementation details
-\begin{document}
- \GetFileInfo{dps.sty}
- \title{The \texttt{dps} Package}
- \author{D. P. Story\\
- Email: \texttt{storyd@owc.edu}}
- \date{processed \today}
- \maketitle
- \tableofcontents
- \let\Email\texttt
- \DocInput{dps.dtx}
- \PrintIndex
-\end{document}
-%</driver>
-% \fi
-% \begin{macrocode}
-%<*package>
-% \end{macrocode}
-% \section{Introduction}
-% The \textsf{dps} Package (Das Puzzle Spiel) provides the commands to create a matching
-% game and associated puzzle. As the user answers each question, another part of the puzzle
-% is filled in. After the user has correctly answered all the questions, the message contained
-% in the puzzle is fully visible. The user answers the question by first clicking the checkbox
-% of that question, reading and solving the question, then by finding the correct answer listed
-% amongst the answer columns. This game was inspired by one of the handout work sheets of my
-% son's eighth grade pre-algebra class.
-%
-% \section{Options}
-% We bring in the \textsf{xkeyval} Package so we can gather our options using
-% it's commands, rather than the default \textsf{keyval} commands.
-% \begin{macrocode}
-\RequirePackage{xkeyval}
-% \end{macrocode}
-% \begin{macro}{nonrandomize}
-% The default behavior is to randomize the questions and answers. With this option, the
-% questions and answers are listed in the order they were written in the source file; good
-% for debugging, and testing the document.
-% \begin{macrocode}
-\DeclareOptionX{nonrandomized}{\werandomizefalse}
-% \end{macrocode}
-% \end{macro}
-% \begin{macro}{viewmode}
-% Used for developing the puzzle. When \texttt{viewmode} is optioned, the puzzle and letters in
-% the puzzle are seen. By adjusting the argument of \cs{insertPuzzle} you can get the distribution
-% of the puzzle that you want. See also the comments preceding the definition of \cs{makeTextField} below.
-% \begin{macrocode}
-\DeclareOptionX{viewmode}{\viewModetrue\previewtrue}
-% \end{macrocode}
-% \end{macro}
-% \begin{macro}{showletters}
-% When this option is taken, in the answer columns, the letters that the answers correspond to appear;
-% and in the puzzle, the question number that corresponds to that letter. Generally, this is used
-% when web is put in \texttt{forpaper} mode, but can be used in ``screen'' mode.
-% \begin{macrocode}
-\DeclareOptionX{showletters}{\showletterstrue}
-% \end{macrocode}
-% \end{macro}
-% \begin{macro}{showanswerlabels}
-% We give the user the option of showing the label for the answer, in the case
-% of for screen presentation.
-%\changes{v1.0}{2006/10/31}
-%{
-% Added the \texttt{showanswerlabels} option
-%}
-% \begin{macrocode}
-\DeclareOptionX{showanswerlabels}
-{%
- \ifeqforpaper\else\def\dpsAitemOptArg{}\fi
-}
-\def\dpsAitemOptArg{[]}
-% \end{macrocode}
-% \end{macro}
-% \begin{macro}{showanswerkey}
-% When this option is taken, the solution key appears in the footer. If the
-% graphicx package is loaded, the answer key is rotated 180 degrees. The
-% answer key is always computed and saved in the macro \cs{AnswerKey},
-% \begin{macrocode}
-\DeclareOptionX{showanswerkey}{\showsolutiontrue}
-% \end{macrocode}
-% \end{macro}
-% \begin{macro}{savedata}
-% When this option is taken, the solution key appears in the footer. If the
-% graphicx package is loaded, the answer key is rotated 180 degrees. The
-% answer key is always computed and saved in the macro \cs{AnswerKey},
-% \begin{macrocode}
-\DeclareOptionX{savedata}{\savepuzzledatatrue}
-% \end{macrocode}
-% \end{macro}
-% \begin{macrocode}
-\newif\ifwerandomize \werandomizetrue
-\newif\ifviewMode \viewModefalse
-\newif\ifshowletters\showlettersfalse
-\newif\ifshowsolution\showsolutionfalse
-\newif\ifsavepuzzledata\savepuzzledatafalse
-\ifeqforpaper\showletterstrue\fi
-% \end{macrocode}
-% The only language localizations are the clever commands that appear in the message box.
-% \begin{macro}{lang}
-% We offer two language options, \texttt{english} (the default) and \texttt{german}. There
-% is a custom option for the author to provide his/her own language localizations.
-% \begin{macrocode}
-\define@choicekey*+{dps.sty}{lang}[\val\nr]{english,german,custom}
-{%
- \ifcase\nr\relax
- \def\dps@lang@type{\input{dps_str_us.def}}
- \or
- \def\dps@lang@type{\input{dps_str_de.def}}
- \or
- \def\dps@lang@type{\input{dps_str_cus.def}}
- \else
- \def\dps@lang@type{\input{dps_str_us.def}}
- \fi
-}{\PackageWarning{dps}{Bad choice for lang, permissible values
-are english, german and custom. Try again}}
-\def\dps@lang@type{\input{dps_str_us.def}}
-% \end{macrocode}
-% \end{macro}
-% \begin{macrocode}
-\AtEndOfPackage{\dps@lang@type}
-\ProcessOptionsX
-% \end{macrocode}
-% \section{Required Packages}
-% In addition to the \textsf{web} and \textsf{eforms} packages, the following are
-% used in the macro package.
-% \begin{macrocode}
-\RequirePackage{verbatim}
-\RequirePackage{calc}
-\RequirePackage{multicol}
-\@ifundefined{nextrandom}{\input{random.tex}}{}
-% \end{macrocode}
-% \begin{macrocode}
-\def\nextrandom{\begingroup
- \ifnum\randomi<\@ne % then initialize with time
- \global\randomi\time
- \global\multiply\randomi388 \global\advance\randomi\year
- \global\multiply\randomi31 \global\advance\randomi\day
- \global\multiply\randomi97 \global\advance\randomi\month
- \message{Randomizer initialized to \the\randomi.}%
- \nextrandom \nextrandom \nextrandom
- \xdef\ds@saveRandomSeed{\the\randomi}%
- \fi
- \count@ii\randomi
- \divide\count@ii 127773 % modulus = multiplier * 127773 + 2836
- \count@\count@ii
- \multiply\count@ii 127773
- \global\advance\randomi-\count@ii % random mod 127773
- \global\multiply\randomi 16807
- \multiply\count@ 2836
- \global\advance\randomi-\count@
- \ifnum\randomi<\z@ \global\advance\randomi 2147483647\relax\fi
- \endgroup
-}
-% \end{macrocode}
-%
-% \section{Switches and things}
-%
-% \begin{macrocode}
-\newif\ifforquestions \forquestionstrue
-\newcount\ds@nCnt
-\newcount\ds@nMax
-\newcount\ds@qNumber\ds@qNumber=0
-\newcount\ds@aNumber\ds@aNumber=0
-\newcount\ds@probCnt \ds@probCnt=0
-\newcount\ds@nCntCols \ds@nCntCols=0
-\newcount\ds@getRanNum
-\newtoks\ds@listIn \ds@listIn={}
-\newtoks\ds@newListIn \ds@newListIn={}
-\newtoks\ds@listOut \ds@listOut={}
-\newtoks\ds@tmpToks \ds@tmpToks={}
-\newtoks\ds@qlistOut \ds@qlistOut={}
-\newtoks\ds@alistOut \ds@alistOut={}
-\newtoks\ds@PuzzleAppearancetoks \ds@PuzzleAppearancetoks={}
-\newtoks\ds@QuesAppearancetoks \ds@QuesAppearancetoks={}
-\newtoks\ds@AnsAppearancetoks \ds@AnsAppearancetoks={}
-\newwrite \ds@question@write
-\ifsavepuzzledata
-\newwrite \ds@savedata
-\immediate\openout \ds@savedata \jobname_data.sav
-\fi
-\setlength{\multicolsep}{\topsep}
-% \end{macrocode}
-% \section{Main Code}
-% \begin{macro}{\makeTextField}
-% \begin{macro}{\PuzzleAppearance}
-% When the user chooses the \texttt{viewmode} option, the underline appear in the puzzle
-% with the letter corresponding to that position; otherwise, a Acrobat text field is created.
-% Note that for letters what have accents, use the hyperref command \cs{texorpdfstring}
-% to give to letters, one for view mode (without accent) and one with accent. See the file
-% \texttt{pmg.tex} for an example of this, look for it in the \cs{DeclarePuzzle} command.
-%
-% The command \cs{PuzzleAppearance} can be used to change the appearance of the text fields for
-% the puzzle.
-%\changes{v1.0}{2006/10/31}
-%{
-% Added a token list to hold any user changes in the appearance of the puzzle, as
-% as suggested by Robert Marik.
-%}
-% \begin{macrocode}
-%\def\PuzzleAppearance#1{\def\pAppearance{#1}}
-\def\PuzzleAppearance#1{\ds@PuzzleAppearancetoks={#1}}
-\ifeqforpaper
- \ifviewMode
- \def\makeTextField#1#2{\def\argii{#2}\ifx\argii
- \ds@myspace\let\ds@ul\relax\else\let\ds@ul\underbar\fi
- \ifshowletters\raisebox{-8pt}{%
- \makebox[0pt][l]{\makebox[16bp][c]{%
- \footnotesize\ds@getProbNumber{#1}{#2}}}}\fi
- \ds@ul{\makebox[16bp][c]{\Hy@pdfstringfalse#1}}}
- \else
- \def\makeTextField#1#2{\def\argii{#2}\ifx\argii\ds@myspace
- \let\ds@ul\relax\else\let\ds@ul\underbar\fi
- \ifshowletters\raisebox{-8pt}{%
- \makebox[0pt][l]{\makebox[16bp][c]{%
- \footnotesize\ds@getProbNumber{#1}{#2}}}}\fi
- \ds@ul{\makebox[16bp][c]{\hfil}}}
- \fi
-\else
- \ifviewMode
- \def\makeTextField#1#2{\ifshowletters\raisebox{-8pt}{%
- \makebox[0pt][l]{\makebox[16bp][c]{%
- \footnotesize\ds@getProbNumber{#1}{#2}}}}\fi
- \underbar{\makebox[16bp][c]{\Hy@pdfstringfalse#1}}}
- \else
- \def\makeTextField#1#2{\ifshowletters
- \raisebox{-8pt}{\makebox[0pt][l]{\makebox[16bp][c]{%
- \footnotesize\ds@getProbNumber{#1}{#2}}}}\fi
- \edef\textfieldTmp{\noexpand\textField[\noexpand\Q{1}%
- \noexpand\S{U}\noexpand\Ff\noexpand\FfReadOnly
- \the\ds@PuzzleAppearancetoks\noexpand\DV{#1}]%
- {puzzle.#2}{16bp}{11bp}}\Hy@pdfstringtrue\textfieldTmp}
- \fi
-\fi
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \begin{macro}{\DeclarePuzzle}
-% \begin{macro}{\insertPuzzle}
-% The puzzle is declare using the \cs{DeclarePuzzle} command. It's argument is a finite
-% number of two argument pairs. For example,
-%\begin{verbatim}
-%\DeclarePuzzle{
-% {H}{H}
-% {e}{e}
-% {l}{l}
-% {l}{l}
-% {o}{o}
-% {,}{punc}
-% {}{space}
-% {J}{J}
-% {\texorpdfstring{\"{u}}{\string\374}}{uml}
-% {g}{g}
-% {e}{e}
-% {n}{n}
-% {!}{punc}
-%}
-%\end{verbatim}
-%The first term of the pair is the letter that appears in the puzzle, in this case, the puzzle is
-%``Hello, J\"{u}rgen!''. Spaces between words are left as empty arguments. A letter that has
-%a special accent can be entered as well; however, for preview mode, use the hyperref command
-%\cs{texorpdfstring}, as illustrated in the example above. (The first argument of \cs{texorpdfstring}
-%will be typeset when the document is in \texttt{viewmode}, the second argument will be inserted
-%into the text field and can be an accented character (it's octal representation).
-%
-%The second term of each pair will form the base name of the form fields created for this document.
-%The second argument must be a JavaScript identifier (basically consist of letters and numbers).
-%Puzzle entries with the same second argument will appear simultaneously when the corresponding
-%question is answered correctly. For example, the puzzle above has two of the letter `e' and
-%to of `l'. As a result, there are only $8$ distinct form names, so $8$ or more questions are
-%needed.
-%
-%Second terms with the name of \texttt{space} and \texttt{punc} are special cases. A \texttt{space} field
-%will be type set as a text field with an empty value (maintaining the spacing of the puzzle); the \texttt{punc}
-%name is recognized as a signal for punctuation, and a text field is not generated for it. (Note, you can
-%give punctuation a field name other than \texttt{punc}, and a text field will be created, and you'll need
-%a question to make that field appear.)
-%
-% You can have more answers than questions, but you cannot have more questions than answers;
-% that is, not questions that have no listed answer and does not correspond to a letter
-% in the puzzle.
-% \begin{macrocode}
-\def\DeclarePuzzle#1{\gdef\puzzleParameters{#1}}
-% \end{macrocode}
-% Use \cs{insertPuzzle} to insert the puzzle at the location desired. The puzzle is placed
-% in a tabular environment. The only argument of this command is the number of columns
-% you want for this tabular environment. For example, \verb!\insertPuzzle{18}! distributes
-% the puzzle so that there are $18$ columns per row, one letter per column.
-% \begin{macrocode}
-\def\insertPuzzle#1{\gdef\nCols{#1}%
- \ifviewMode\Hy@pdfstringfalse\else\Hy@pdfstringtrue\fi
- \expandafter\aeb@Puzzle\expandafter{\puzzleParameters}}%
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \begin{macro}{\rowsep}
-% This command is used to adjust the space between row of the tabular environment
-% for the puzzle. The default is \verb!\rowsep{1ex}!.
-% \begin{macrocode}
-\def\rowsep#1{\gdef\@rowsep{[#1]}}\rowsep{\rowsep@default}
-\def\rowsep@default{1ex}
-% \end{macrocode}
-% \end{macro}
-% This code create the tabular environment, creating a new row when necessary,
-% and inserts the text field or typesets the puzzle (in the case of \texttt{viewmode}).
-% \begin{macrocode}
-\def\eq@tabSep{&}\def\ds@punc{punc}
-\def\aeb@Puzzle#1{\edef\eq@tabEnd{\noexpand\\\@rowsep}%
- \aeb@@Puzzle#1\relax\relax}%
-\def\aeb@@Puzzle{\begin{tabular*}{\linewidth}{*{\nCols}l}\@aebPuzzlei}%
-\def\@aebPuzzlei#1#2{\ifx#1\relax\gdef\nextPuzzleChar{\@aebPuzzleDone}%
- \else\gdef\nextPuzzleChar{\@aebPuzzleii{#1}{#2}}\fi\nextPuzzleChar}%
-\def\@aebPuzzleii#1#2{\makeTextField{#1}{#2}\@takeaPeek}
-\def\@takeaPeek#1#2{\def\argii{#2}\ifx\argii\ds@punc
- \def\@puzzNext{#1\@setSep@aebPuzzleii}%
- \else\def\@puzzNext{\@setSep@aebPuzzleii{#1}{#2}}\fi\@puzzNext}
-\def\@setSep@aebPuzzleii{\global\advance\ds@nCntCols1\relax
- \ifnum\ds@nCntCols=\nCols\expandafter\eq@tabEnd \global\ds@nCntCols=0
- \else\expandafter\eq@tabSep\fi\@aebPuzzlei}%
-\def\@aebPuzzleDone{\end{tabular*}\ds@buildAnswerKey}%
-% \end{macrocode}
-% \begin{macro}{\AnswerKey}
-% The command \cs{AnswerKey} is defined at the end of the \cs{insertPuzzle} command
-% and is available thereafter for insertion into the document. If the \texttt{showanswerkey}
-% option is taken, it is displayed at the bottom of the page. If the \texttt{savedata}
-% option is taken, the answer key is save to a file along with the random seed that generated
-% this answer key. The file name containing the puzzle data is \cs{jobname\_data.sav}.
-% \begin{macrocode}
-\def\ds@buildAnswerKey
-{%
- {% local
- \count0=0 \toks0={}%
- \loop
- \advance\count0by1
- \xdef\AnswerKey{\the\toks0
- \the\count0--\noexpand
- \csname dps@probLetter\the\count0\noexpand\endcsname; }%
- \toks0 = \expandafter{\AnswerKey}%
- \ifnum\count0 < \ds@qNumber\repeat
- }%
- \ifshowsolution
- \cfooter{\footnotesize\@ifundefined{rotatebox}{\AnswerKey}%
- {\rotatebox{180}{\AnswerKey}}}%
- \fi
- \ifsavepuzzledata
- \AtEndDocument{\ds@writePuzzleData}%
- \fi
-}
-\def\ds@writePuzzleData{%
- \let\verbatim@out\ds@savedata
- \dps@IWVO{Initial seed: \string\randomi=\ds@saveRandomSeed}%
- \dps@IWVO{Solution Key: \AnswerKey}%
-}
-% \end{macrocode}
-% \end{macro}
-% \section{Questions and Answers}
-% \begin{environment}{Composing}
-% This is the environments in which the composing of questions and answers are made.
-% Use the \texttt{cQ} and \texttt{cA} for this purpose.
-% \begin{macrocode}
-\newenvironment{Composing}
-{\global\ds@qNumber=0 \global\ds@aNumber=0}
-{\aftergroup\ds@publishRandomLists}
-% \end{macrocode}
-% \end{environment}
-% \begin{environment}{cQ}
-% \begin{environment}{cA}
-% Here are the two environment for composing questions and answers. The argument
-% of each environment corresponds to a form field in the puzzle. Each of these
-% environments are verbatim write environments; they write each question and solution
-% to a separate \texttt{.cut} file. These individual files are ultimately input
-% in a random order.
-% \begin{macrocode}
-\newenvironment{cQ}[1]
-{%
- \global\advance\ds@qNumber1
- \immediate\openout \ds@question@write \jobname_q\the\ds@qNumber.cut
- \let\verbatim@out\ds@question@write
- \dps@IWVO{\noexpand\dpsQ{#1}}%
- \verbatimwrite}
-{%
- \endverbatimwrite
- \immediate\closeout \ds@question@write
-}
-% \end{macrocode}
-% The cA environment has an optional argument. This optional argument is only used
-% when the document is compiled with the showletters option. The value of the argument
-% is a letter to appear in the answers column. Normally, one of the first entries in the
-% \cs{DeclarePuzzle} command is used. Cases where you would want to include this optional
-% argument are (1) when giving an answer that does not correspond to a question; (2) the
-% letter is capitalized, suggesting a proper name or the beginning of a sentence, use the
-% optional argument to list the letter in lower case.
-% \begin{macrocode}
-\newenvironment{cA}[2][]
-{%
- \def\argi{#1}\global\advance\ds@aNumber1
- \immediate\openout \ds@question@write \jobname_a\the\ds@aNumber.cut
- \let\verbatim@out\ds@question@write
- \let\protect\noexpand
- \dps@IWVO{\noexpand\dpsA\ifshowletters
- \ifx\argi\@empty\else[#1]\fi\fi{#2}}%
- \verbatimwrite}
-{%
- \endverbatimwrite
- \immediate\closeout \ds@question@write
-}
-% \end{macrocode}
-% \end{environment}
-% \end{environment}
-% \begin{macro}{\QuesAppearance}
-% \begin{macro}{\AnsAppearance}
-% These two commands can be used to change the appearance of the checkboxes for the questions and answers.
-% When the \texttt{forpaper} \textsf{web} option is taken, these have no effect.
-% \begin{macrocode}
-\def\QuesAppearance#1{\ds@QuesAppearancetoks={#1}}
-\def\AnsAppearance#1{\ds@AnsAppearancetoks={#1}}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \begin{macro}{\dpsQ}
-% \begin{macro}{\dpsA}
-% \begin{macro}{\afterQhookA}
-% \begin{macro}{\OnFocusQhookAA}
-% The next two commands place the check boxes, the argument is the name of the form
-% field that corresponds to one of the letters in the puzzle.
-%
-% The commands \cs{dpsQ} and \cs{dpsA} are the ones that produce the checkboxes, and define the
-% JavaScript actions. These two can be redefined as needed, but be sure to preserve the JS
-% functionality.
-%
-% The two commands \cs{afterQhookA} and \cs{OnFocusQhookAA} are commands that can be redefined
-% for additional JS action, the first is a hook into the mouse up action, and the second is
-% a hook to the on focus action.
-% \begin{macrocode}
-\let\afterQhookA\@gobble
-\let\OnFocusQhookAA\@gobble
-% \end{macrocode}
-% Set the checkboxes and JS action for questions. Allow also, changes to appearance
-% through the \cs{QuesAppearance} command.
-% \begin{macrocode}
-\newcommand{\dpsQ}[1]{\item\relax\ifeqforpaper\else
- \edef\checkboxTmp{\noexpand\checkBox[\the\ds@QuesAppearancetoks
- \noexpand\A{\noexpand\JS{activeQuestion = event.target.name;
- clearRedCrosses(); \noexpand\afterQhookA{#1}}}%
- \noexpand\AA{\noexpand\AAOnFocus{\noexpand\JS{%
- this.resetForm(["ckbxQ"]); \noexpand\OnFocusQhookAA{#1}}}}]%
- {ckbxQ.#1}{14bp}{11bp}{Yes}}\makebox[0pt][r]{\checkboxTmp\enspace}%
- \fi\ignorespaces}
-% \end{macrocode}
-% Set the checkboxes and JS action for answers. Allow also, changes to appearance
-% through the \cs{AnsAppearance} command. This command obeys the \texttt{showanswerlabels}
-% option by re-defining the command \cs{dpsAitemOptArg}. The default definition
-% is \verb!\def\dpsAitemOptArg{[]}!, which cancels the display of the item labels.
-% \begin{macrocode}
-\newcommand{\dpsA}[2][]{\expandafter\item\dpsAitemOptArg\relax
- \ifeqforpaper\else
- \edef\checkboxTmp{\noexpand\checkBox[\the\ds@AnsAppearancetoks
- \noexpand\A{\noexpand\JS{processChoice("#2")}}]%
- {ckbxA.#2}{14bp}{11bp}{Yes}}%
- \makebox[0pt][r]{\checkboxTmp\enspace}%
- \fi
- \def\argi{#1}%
- \ifshowletters
- \ifx\argi\@empty
- \let\getLetterNext\relax
- \let\ds@foundLetter=0\def\ds@currFN{#2}%
- \def\getLetterNext{\ds@typesetPuzzleLetter}%
- \expandafter\getLetterNext
- \else
- \makebox[0pt][r]{\Hy@pdfstringfalse#1\enspace\kern4bp}%
- \fi
- \fi
- \ignorespaces
-}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \begin{macrocode}
-\def\ds@typesetPuzzleLetter{%
- \expandafter\typeset@PuzzleLetter\expandafter{\puzzleParameters}}
-\def\typeset@PuzzleLetter#1{\typeset@@PuzzleLetter#1\relax\relax}%
-\def\typeset@@PuzzleLetter#1#2{%
- \ifx#1\relax
- \gdef\nextPuzzleLetter{\relax}%
- \else
- \gdef\nextPuzzleLetter{\typeset@PuzzleLetteri{#1}{#2}}%
- \fi
- \nextPuzzleLetter
-}
-\def\typeset@PuzzleLetteri#1#2{\def\argii{#2}\ifx\argii\ds@currFN
- \if\ds@foundLetter0\makebox[0pt][r]{%
- \Hy@pdfstringfalse#1\enspace\kern4bp}\let\ds@foundLetter=1\fi
- \expandafter\typeset@@PuzzleLetter
- \else\expandafter\typeset@@PuzzleLetter\fi}
-% \end{macrocode}
-% This command is called at \verb!\end{Composing}!, which, in turn, calls
-% the macros \cs{ds@randomizeQuestionList} and \cs{ds@randomizeAnswerList} which randomly
-% permutes the \verb!1, 2, ... \the\ds@qNumber! and \verb!1, 2, ... \the\ds@aNumber!,
-% where \cs{ds@qNumber} and \cs{ds@aNumber} are the number of questions and answers,
-% respectively.
-% \begin{macrocode}
-\def\ds@publishRandomLists{%
- \ds@randomizeQuestionList{\the\ds@qNumber}%
- \ds@randomizeAnswerList{\the\ds@aNumber}%
-}
-\def\ds@myspace{space}
-\def\ds@getProbNumber#1#2{%
- \gdef\ds@currentArgi{#1}\gdef\ds@currentArgii{#2}%
- \ifx\ds@currentArgii\ds@myspace\def\ds@probNumNext{\relax}\else
- \def\ds@probNumNext{%
- \@ifundefined{dps@probNum#2}{\global\advance\ds@probCnt1
-% \typeout{\ds@probCnt = \the\ds@probCnt}%
- \ds@@getProbNumber{\the\ds@probCnt}%
- }{\csname dps@probNum#2\endcsname}%
- }%
- \fi
- \ds@probNumNext
-}
-\def\ds@@getProbNumber#1{%
- {\count0=0 \let\\=\ds@getNthOne\the\ds@qlistOut}%
- \csname dps@probNum\ds@currentArgii\endcsname
-}
-\def\ds@getNthOne#1{\advance\count0by1
- \ifnum\ds@probCnt=#1
- \expandafter
- \xdef\csname dps@probNum\ds@currentArgii\endcsname
- {\the\count0 }%
-%\typeout{\the\count0, and \ds@currentArgi}%
- \expandafter
- \xdef\csname dps@probLetter\the\count0\endcsname
- {\expandafter\noexpand\ds@currentArgi}%
- \fi
-}
-% \end{macrocode}
-% \begin{macro}{\writeComposingEnv}
-% This is a helper macro. After you declare your puzzle, \cs{DeclarePuzzle},
-% you can place this command just after, if needed, like so
-%\begin{verbatim}
-%\writeComposingEnv
-%\begin{document}
-%\end{document}
-%\end{verbatim}
-%In the case where \cs{DeclarePuzzle} is in the preamble; above, we begin the doc
-% and end the doc; assuming you have not developed your questions yet. The command
-% writes to the file \cs{jobname\_comp.def}. This file will be a skeleton of your
-% Composing environment, with correct labeling. Copy and paste it into your document
-% in some appropriate location, and begin writing your questions.
-% \begin{macrocode}
-\def\writeComposingEnv{%
- \newwrite \ds@composing@write
- \immediate\openout \ds@composing@write \jobname_comp.def
- \let\verbatim@out\ds@composing@write
- \dps@IWVO{\string\begin{Composing}}%
- \dps@IWVO{}%
- \expandafter\write@ComposingEnv\expandafter{\puzzleParameters}%
-}
-\def\write@ComposingEnv#1{\write@@ComposingEnv#1\relax\relax}%
-\def\write@@ComposingEnv#1#2{\ifx#1\relax
- \gdef\nextPuzzlePair{%
- \dps@IWVO{\string\end{Composing}}%
- \immediate\closeout \ds@composing@write}%
- \else\gdef\nextPuzzlePair{\write@@@ComposingEnv{#1}{#2}}\fi
- \nextPuzzlePair}%
-\def\write@@@ComposingEnv#1#2{%
- \gdef\ds@currentArgi{#1}\gdef\ds@currentArgii{#2}%
- \ifx\ds@currentArgii\ds@myspace
- \def\ds@probNumNext{\write@@ComposingEnv}%
- \else
- \ifx\ds@currentArgii\ds@punc
- \def\ds@probNumNext{\write@@ComposingEnv}\else
- \def\ds@probNumNext{%
- \@ifundefined{dps@compQ#2}{% write to file
- \expandafter\gdef\csname dps@compQ#2\endcsname{found}%
- \dps@IWVO{\string\begin{cQ}{\noexpand#1}}%
- \dps@IWVO{\string\end{cQ}}%
- \dps@IWVO{\string\begin{cA}{\noexpand#1}}%
- \dps@IWVO{\string\end{cA}}%
- \dps@IWVO{}%
- }{}%
- \write@@ComposingEnv
- }%
- \fi\fi
- \ds@probNumNext
-}
-% \end{macrocode}
-% \end{macro}
-% A standard \cs{verbatim} write used in exerquiz and other package in the AeB family.
-% \begin{macrocode}
-\def\verbatimwrite{\@bsphack
- \let\do\@makeother\dospecials
- \catcode`\^^M\active \catcode`\^^I=12
- \def\verbatim@processline{%
- \immediate\write\verbatim@out
- {\the\verbatim@line}}%
- \verbatim@start}
-\def\endverbatimwrite{\@esphack}
-\def\dps@IWVO{\immediate\write\verbatim@out}
-% \end{macrocode}
-% \cs{ds@populateList} is a utility command, its argument is a positive integer, \texttt{n},
-% and it generates a list of the form \verb!\\{1}\\{2}...\\{n}!. This listing is later
-% randomly permuted by \cs{ds@randomizeQuestionList} and \cs{ds@randomizeAnswerList}.
-% \begin{macrocode}
-\def\ds@populateList#1{%
- \ds@listIn = {}%
- \ds@nCnt=0
- \@whilenum \ds@nCnt < #1\do {%
- \advance\ds@nCnt1
- \edef\ds@listInHold{\the\ds@listIn\noexpand\\{\the\ds@nCnt}}%
- \ds@listIn = \expandafter{\ds@listInHold}%
- }%
-}
-% \end{macrocode}
-% Used in \cs{ds@randomizeList} to build the permuted list of numbers.
-% \begin{macrocode}
-\def\ds@processi#1{\advance\ds@nCnt1
- \ifnum\ds@nCnt=\ds@getRanNum\edef\ds@listOutHold{\the\ds@listOut}%
- \global\ds@listOut=\expandafter{\ds@listOutHold\\{#1}}%
- \else
- \edef\ds@listInHold{\the\ds@newListIn}%
- \ds@tmpToks = \expandafter{\ds@listInHold\\{#1}}%
- \ds@newListIn = \expandafter{\the\ds@tmpToks}%
- \fi
-}
-% \end{macrocode}
-% Used in \cs{displayRandomizedQuestions} to input the questions.
-% \begin{macrocode}
-\def\ds@processii#1{\input{\jobname_q#1.cut}}
-% \end{macrocode}
-% Used in \cs{displayRandomizedAnswers} to input the answers.
-% \begin{macrocode}
-\def\ds@processiii#1{\input{\jobname_a#1.cut}}
-% \end{macrocode}
-% Used in \cs{displayRandomizedAnswersLeftPanel} to input the top half
-% of the permuted list.
-% \begin{macrocode}
-\def\ds@processL#1{\advance\count0by1 %\divide\ds@aNumber2
- \ifnum\count0>\ds@aNumber\relax\else\input{\jobname_a#1.cut}\fi}
-% \end{macrocode}
-% Used in \cs{displayRandomizedAnswersRightPanel} to input the bottom half
-% of the permuted list.
-% \begin{macrocode}
-\def\ds@processR#1{\advance\count0by1 %\divide\ds@aNumber2
- \ifnum\count0>\ds@aNumber\relax\input{\jobname_a#1.cut}\fi}
-% \end{macrocode}
-% \begin{macro}{\displayRandomizedQuestions}
-% \begin{macro}{\displayRandomizedAnswers}
-% \begin{macro}{\displayRandomizedAnswersLeftPanel}
-% \begin{macro}{\displayRandomizedAnswersRightPanel}
-% These are user commands that actually display the randomized questions
-% and answers.
-% \begin{macrocode}
-\def\displayRandomizedQuestions{\let\\=\ds@processii\the\ds@qlistOut}
-\def\displayRandomizedAnswers{\let\\=\ds@processiii\the\ds@alistOut}
-\def\displayRandomizedAnswersLeftPanel{{\let\\=\ds@processL\count0=0
- \divide\ds@aNumber2 \the\ds@alistOut}}
-\def\displayRandomizedAnswersRightPanel{{\let\\=\ds@processR\count0=0
- \divide\ds@aNumber2 \the\ds@alistOut}}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% Develop a random permuted list for the questions.
-% \begin{macrocode}
-\def\ds@randomizeQuestionList#1{%
- \global\ds@listIn={}\global\ds@newListIn={}\global\ds@listOut={}%
- \global\ds@tmpToks={}%\global\ds@qlistOut={}\global\ds@alistOut={}%
- \ds@nMax=#1\relax\ds@populateList{\the\ds@nMax}%
- \global\forquestionstrue
- \ifwerandomize
- \expandafter\ds@randomizeList
- \else
-% \global\let\ds@qlistOut=\ds@listIn
- \global\ds@qlistOut=\expandafter{\the\ds@listIn}
- \fi
-}
-% \end{macrocode}
-% Develop a random permuted list for the answers. Note that \cs{ifwerandomize}
-% we randomize, else, the output list is the same as the input list.
-% \begin{macrocode}
-\def\ds@randomizeAnswerList#1{%
- \global\ds@listIn={}\global\ds@newListIn={}\global\ds@listOut={}%
- \global\ds@tmpToks={}%\global\ds@qlistOut={}\global\ds@alistOut={}%
- \ds@nMax=#1\relax\ds@populateList{\the\ds@nMax}%
- \global\forquestionsfalse
- \ifwerandomize
-% \nextrandom \nextrandom \nextrandom
- \expandafter\ds@randomizeList
- \else
-% \global\let\ds@alistOut=\ds@listIn
- \global\ds@alistOut=\expandafter{\the\ds@listIn}%
- \fi
-}
-% \end{macrocode}
-% The loop that does all the work for randomizing.
-% \begin{macrocode}
-\def\ds@randomizeList{%
- \let\\=\ds@processi
- \setrannum{\ds@getRanNum}{1}{\ds@nMax}%
- \ds@nCnt=0\relax
-% \typeout{LISTING: \the\ds@listIn}%
- \the\ds@listIn
- \ds@loopTest
-}
-% \end{macrocode}
-% The loop that does all the work for randomizing.
-% \begin{macrocode}
-\def\ds@loopTest{\advance\ds@nMax-1\relax
- \ifnum\ds@nMax>0\relax
- \def\@next{%
- \ds@listIn=\expandafter{\the\ds@newListIn}%
- \ds@newListIn={}\ds@randomizeList}%
- \else
- \let\@next\relax
- \ifforquestions
- \global\ds@qlistOut=\expandafter{\the\ds@listOut}%
-% \typeout{\ds@qlistOut = \the\ds@qlistOut}%
- \else
-% \global\ds@alistOut=\expandafter{\@tmp}
- \global\ds@alistOut=\expandafter{\the\ds@listOut}%
-% \typeout{\ds@alistOut = \the\ds@alistOut}%
- \fi
- \fi
- \@next
-}
-% \end{macrocode}
-% \begin{macro}{\placeMessageField}
-% The command inserts the required message field. The optional
-% first parameters enables the author to change the appearance
-% of the field, the second two required arguments are the width
-% and the height of the text field.
-% \begin{macrocode}
-\newcommand{\placeMessageField}[3][]{%
- \ifeqforpaper\else\textField[#1\Ff\FfMultiline]{report}{#2}{#3}\fi
-}
-% \end{macrocode}
-% \end{macro}
-% \section{Miscellaneous Settings}
-% \begin{macro}{\threshold}
-% \begin{macro}{\penaltypoints}
-% \begin{macro}{\passing}
-% Threshold for number of incorrect answers for trying to answer one question.
-% If the threshold is exceeded, \cs{dspenaltypoints} are added to the final
-% points. Passing is missing no more than \cs{dspassing}.
-% \begin{macrocode}
-\newcommand{\threshold}[1]{\def\dsthreshold{#1}}
-\threshold{3}
-\newcommand{\penaltypoints}[1]{\def\dspenaltypoints{#1}}
-\penaltypoints{3}
-\newcommand{\passing}[1]{\def\dspassing{#1}}
-\passing{4}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \begin{macrocode}
-%</package>
-% \end{macrocode}
-% \section{Language Cutomizations}
-% \begin{macrocode}
-%<*english>
-\def\chooseQ{"You must choose a question to answer before you answer!"}
-\def\triedTooMuch{"You have tried this problem too many times,
- I'm adding "
- + \dspenaltypoints
- + " points, and resetting the penalty counter. Bad boy/girl!"}
-\def\congratFinished{"Congratulations! You finished the puzzle"
- +((nMissed==0) ? " without missing a single problem, amazing!"
- : ", but you missed " + nMissed + " questions in the process!")}
-\def\regretPleased{(( nMissed > n )
- ? "I regret to report that you did not pass the test because
- you missed too many questions."
- : "I am pleased to report that you passed the test!")}
-\def\reportPenaltyPoints{"The number of penalty points is "
- + nPenaltyPoints +"."}
-\def\finalPenaltyScore{"Final penalty score is " + nTotalPenaltyPoints + ". "}
-\def\aPenaltyScale{[-1,0], [0,4], [4, 10], [10,25], [25,5000]}
-\def\aPenaltyMsgs
-{%
- "Perfect!",
- "Very nice performance!",
- "This is not looking good. Perhaps a review is in order!",
- "Are you trying? No one could do so badly, you only need a seventh grade education!",
- "You're hopeless!"
-}
-%</english>
-%<*german>
-\def\chooseQ{"Du musst erst eine Frage ausw\string\344hlen bevor Du antwortest!"}
-\def\triedTooMuch{"Du hast es leider zu oft versucht, ich z\string\344hle "
- + \dspenaltypoints
- + " Punkte dazu und setze den Z\string\344hler dann zur\string\374ck. Bitte streng Dich an!"}
-\def\congratFinished{"Herzlichen Gl\string\374ckwunsch! Du hast das Puzzle beendet"
- +((nMissed==0) ? " ohne auch nur einen Fehler zu machen, wunderbar!"
- : ", aber leider " + nMissed + " Mal falsch geantwortet!")}
-\def\regretPleased{(( nMissed > n )
- ? "Ich bedauere Dir mitteilen zu m\string\374ssen, dass Du den Test leider nicht bestanden hast, weil Du zu viele Fragen falsch beantwortet hast."
- : "Ich bin \string\344usserst erfreut Dir mitteilen zu d\string\374rfen, dass Du den Test bestanden hast!")}
-\def\reportPenaltyPoints{"Die Anzahl der Strafpunkte ist " + nPenaltyPoints +"."}
-\def\finalPenaltyScore{"Die Gesamtanzahl der Strafpunkte ist damit " + nTotalPenaltyPoints + ". "}
-\def\aPenaltyScale{[-1,0], [0,4], [4, 10], [10,25], [25,5000]}
-\def\aPenaltyMsgs
-{%
- "Perfekt!",
- "Sehr gute Vorstellung!",
- "Es sieht nicht sonderlich gut aus. Vielleicht w\string\344re eine Wiederholung gut!",
- "R\string\344tst Du eigentlich nur? Niemand kann wirklich so schlecht sein. Das ist Stoff aus der siebten Klasse!",
- "Du bist ein hoffnungsloser Fall!"
-}
-%</german>
-% \end{macrocode}
-% \section{JavaScript Support}
-% \begin{macrocode}
-%<*package>
-\begin{insDLJS}[processChoice]{match}{JS Update of Matching Puzzle}
-var missesByQuestion = new Array();
-var nMissed = 0;
-var nPenaltyPoints = 0;
-var activeQuestion = "";
-function processChoice(fieldname)
-{
- // Get the question field that corresponds to this question,
- // see if checked.
- var f = this.getField("ckbxQ."+fieldname);
- if ( (f != null) && (f.isBoxChecked(0)) ) { // right
- clearRedCrosses ();
- this.resetForm(["puzzle."+fieldname]);
- event.target.textColor = ["RGB", 0, 0.6, 0];
- f.strokeColor = ["RGB", 0, 0.6, 0];
- f.readonly = true;
- event.target.readonly=true;
- try { afterCorrectChoiceHook() } catch(e) {};
- checkForFinished(\dspassing);
- } else { // wrong
- if ( activeQuestion != "" ) var h = this.getField(activeQuestion);
- if ( (activeQuestion=="") || (h.readonly) ) { // active question already answered
- event.target.value = "Off";
- var g = this.getField("report");
- str = \chooseQ;
- g.value = str;
- var to = app.setTimeOut("clearMessages()", 2000);
- } else {
- event.target.style = style.cr;
- event.target.textColor = color.red;
- ++nMissed;
- if ( typeof missesByQuestion[activeQuestion] !="number" )
- missesByQuestion[activeQuestion] = 1;
- else
- missesByQuestion[activeQuestion] += 1;
- if (missesByQuestion[activeQuestion] > \dsthreshold) {
- var f = this.getField("report");
- str = \triedTooMuch;
- f.value = str;
- nPenaltyPoints += \dspenaltypoints;
- missesByQuestion[activeQuestion] = 0;
- clearRedCrosses ();
- var to = app.setTimeOut("clearMessages()", 2000)
- }
- }
- }
-}
-function clearMessages()
-{
- var f = this.getField("report");
- f.value = "";
-}
-function clearRedCrosses ()
-{
- var g = this.getField("ckbxA");
- h = g.getArray();
- for ( i=0; i < h.length; i++) {
- if ( h[i].style == style.cr) h[i].checkThisBox(0,false);
- h[i].style = style.ch;
- }
- }
-function checkForFinished(n)
-{
- var f = this.getField("puzzle");
- var g = f.getArray();
- var anyEmpty = false;
- for ( var i=0; i < g.length; i++) {
- if ( (g[i].name != "puzzle.space") && (g[i].value.replace(/\s/g,"") == "") ) {
- anyEmpty = true;
- break;
- }
- }
- var nTotalPenaltyPoints=nMissed + nPenaltyPoints;
- if ( !anyEmpty ) {
- try { dpsFinishedHook() } catch (e) {};
- var f = this.getField("report");
- str = \congratFinished
- + "\n" + \regretPleased
- + "\n" + \reportPenaltyPoints
- + "\n" + \finalPenaltyScore
- + " " + finalRating(nTotalPenaltyPoints);
- f.value = str;
- }
-}
-function finalRating(n) {
- var aPenaltyScale = new Array( \aPenaltyScale\space);
- var aPenaltyMsgs = new Array( \aPenaltyMsgs\space);
- for ( var i=0; i<aPenaltyScale.length; i++)
- if ( (n > aPenaltyScale[i][0]) && (n <= aPenaltyScale[i][1]) )
- return aPenaltyMsgs[i];
-}
-\end{insDLJS}
-%</package>
-% \end{macrocode}
-% \Finale
-\endinput
+% \iffalse +%<*copyright> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% dps.sty package, %% +%% Copyright (C) 2006--2020 D. P. Story %% +%% dpstory@acrotex.net %% +%% %% +%% This program can redistributed and/or modified under %% +%% the terms of the LaTeX Project Public License %% +%% Distributed from CTAN archives in directory %% +%% macros/latex/base/lppl.txt; either version 1 of the %% +%% License, or (at your option) any later version. %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%</copyright> +%<package>\NeedsTeXFormat{LaTeX2e} +%<package>\ProvidesPackage{dps} +%<package> [2020/06/03 v1.7 Das Puzzle Spiel (dps)] +%<*driver> +\documentclass{ltxdoc} +\usepackage[colorlinks,hyperindex=false]{hyperref}[2012/10/12] +\usepackage{fancyvrb} +\pdfstringdefDisableCommands{\let\\\textbackslash}% +\EnableCrossrefs \CodelineIndex \RecordChanges +\bgroup\ttfamily +\gdef\brpr#1{\char123\relax#1\char125\relax}\egroup +\let\darg\brpr +\let\env\texttt +\let\opt\texttt +\let\app\textsf +\def\visispace{\symbol{32}} +\def\ameta#1{\ensuremath{\langle\textit{\texttt{#1}}\rangle}} +\def\meta#1{\textsl{\texttt{#1}}} +\def\SUB#1{\ensuremath{{}_{\mbox{\scriptsize\ttfamily#1}}}} +\def\ltag{<}\def\rtag{>} +\def\EXCL{!} +\let\app\textsf\let\pkg\textsf +%\OnlyDescription % comment out for implementation details +\InputIfFileExists{aebdocfmt.def}{\PackageInfo{dps}{Inputting aebdocfmt.def}} + {\def\IndexOpt{\DescribeMacro}\def\IndexKey{\DescribeMacro} \let\setupFullwidth\relax + \PackageInfo{dps}{aebdocfmt.def cannot be found}} +\begin{document} + \GetFileInfo{dps.sty} + \title{The \texttt{dps} Package} + \author{D. P. Story\\ + Email: \texttt{dpstory@acrotex.net}} + \date{processed \today} +\value{secnumdepth}=3 +\value{tocdepth}=3 + \maketitle + \tableofcontents + \let\Email\texttt + \DocInput{dps.dtx} +\IfFileExists{\jobname.ind}{\newpage\setupFullwidth\PrintIndex}{\paragraph*{Index} The index goes here.\\Execute + \texttt{makeindex -s gind.ist -o dps.ind dps.idx} on the command line and recompile + \texttt{dps.dtx}.} +\IfFileExists{\jobname.gls}{\PrintChanges}{\paragraph*{Change History} The list of changes goes here.\\Execute + \texttt{makeindex -s gglo.ist -o dps.gls dps.glo} on the command line and recompile + \texttt{dps.dtx}.} +\end{document} +%</driver> +% \fi +% \MakeShortVerb{|} +% \InputIfFileExists{aebdonotindex.def}{\PackageInfo{eforms}{Inputting aebdonotindex.def}} +% {\PackageInfo{eforms}{aebdonotindex.def cannot be found}} +% \begin{macrocode} +%<*package> +% \end{macrocode} +% \section{Introduction} +% The \textsf{dps} Package (Das Puzzle Spiel) provides the commands to create a matching +% game and associated puzzle. As the user answers each question, another part of the puzzle +% is filled in. After the user has correctly answered all the questions, the message contained +% in the puzzle is fully visible. The user answers the question by first clicking the checkbox +% of that question, reading and solving the question, then by finding the correct answer listed +% amongst the answer columns. This game was inspired by one of the handout work sheets of my +% son's eighth grade pre-algebra class. +% +% \section{Options} +% We bring in the \textsf{xkeyval} Package so we can gather our options using +% it's commands, rather than the default \textsf{keyval} commands. +% \begin{macrocode} +\RequirePackage{xkeyval} +% \end{macrocode} +% \leavevmode\IndexOpt{nonrandomized}\ignorespaces +% The default behavior is to randomize the questions and answers. With this option, the +% questions and answers are listed in the order they were written in the source file; good +% for debugging, and testing the document. We also have the option \IndexOpt[\protect\EXCL]{!nonrandomized}\opt{!nonrandomized} +% to `cancel' \opt{nonrandomized}. +% \begin{macrocode} +\DeclareOptionX{nonrandomized}{\werandomizefalse} +\DeclareOptionX{!nonrandomized}{\werandomizetrue} +% \end{macrocode} +% \leavevmode\IndexOpt{viewmode}\ignorespaces +% Used for developing the puzzle. When \texttt{viewmode} is optioned, the puzzle and letters in +% the puzzle are seen. By adjusting the argument of \cs{insertPuzzle} you can get the distribution +% of the puzzle that you want. See also the comments preceding the definition of \cs{makeTextField} below. +% The \IndexOpt[\protect\EXCL]{!viewmode}\opt{!viewmode} option cancels the \opt{viewmode} option. +% \begin{macrocode} +\DeclareOptionX{viewmode}{\viewModetrue\previewtrue} +\DeclareOptionX{!viewmode}{\viewModefalse\previewfalse} +% \end{macrocode} +% \leavevmode\IndexOpt{showletters}\ignorespaces +% When this option is taken, in the answer columns, the letters that the answers correspond to appear; +% and in the puzzle, the question number that corresponds to that letter. Generally, this is used +% when web is put in \texttt{forpaper} mode, but can be used in ``screen'' mode. The convenience +% option of \IndexOpt[\protect\EXCL]{!showletters}\opt{!showletters} is also provided. +% \begin{macrocode} +\DeclareOptionX{showletters}{\showletterstrue} +\DeclareOptionX{!showletters}{\showlettersfalse} +% \end{macrocode} +% \leavevmode\IndexOpt{showanswerlabels}\ignorespaces +% We give the user the option of showing the label for the answer, in the case +% of for screen presentation. +%\changes{v1.0}{2006/10/31} +%{ +% Added the \string\texttt{showanswerlabels} option +%} +% \begin{macrocode} +\DeclareOptionX{showanswerlabels} +{% + \ifeqforpaper\else\def\dpsAitemOptArg{}\fi +} +\DeclareOptionX{!showanswerlabels}{% + \def\dpsAitemOptArg{[]}} +\def\dpsAitemOptArg{[]} +% \end{macrocode} +% \leavevmode\IndexOpt{showanswerkey}\ignorespaces +% When this option is taken, the solution key appears in the footer. If the +% graphicx package is loaded, the answer key is rotated 180 degrees. The +% answer key is always computed and saved in the macro \cs{AnswerKey}. Selecting +% \opt{showanswerkey} also activates the \opt{showletters} option. +% The convenience option \IndexOpt[\protect\EXCL]{!showanswerkey}\opt{!showanswerkey} is also +% provided. +% \begin{macrocode} +\DeclareOptionX{showanswerkey}{\showsolutiontrue + \ExecuteOptionsX{showletters}} +\DeclareOptionX{!showanswerkey}{\showsolutionfalse} +% \end{macrocode} +% \paragraph*{Options for posing questions.} There are two methods of posing longer questions: +% (1) (\opt{usebtnappr}) Place these questions in the appearance of a button; or +% (2) (\opt{uselayers}) Place the questions in their own layer (OCG). Only one of these +% two options is allowed. Neither option is also permitted (short questions only). +% \begin{macrocode} +% \end{macrocode} +% \leavevmode +% \IndexOpt{usebtnappr}\ignorespaces +% A required option when you want to pose longer questions. We have a complex +% workflow for placing the questions as a button appearance. This option brings in supporting commands. +% \begin{macrocode} +\DeclareOptionX{usebtnappr}{\usebtnapprtrue + \ifuseocgappr + \PackageWarningNoLine{dps} + {Options usebtnappr and uselayers both used.\MessageBreak + Will use the uselayers option}% + \usebtnapprfalse + \let\dpsInputBtnAppr\relax + \else + \def\dpsInputBtnAppr{\InputIfFileExists{usebtnappr.def}{}{}}% + \fi} +\let\dpsInputBtnAppr\relax +% \end{macrocode} +% \leavevmode +% \IndexOpt{uselayers} +% A required option when you want to pose longer questions. Longer questions +% are placed in OCG (layers). This option brings in supporting commands. +% \begin{macrocode} +\DeclareOptionX{uselayers}{\useocgapprtrue + \ifusebtnappr + \PackageWarningNoLine{dps} + {Options usebtnappr and uselayers both used.\MessageBreak + Will use the usebtnappr option}% + \useocgapprfalse + \let\dpsInputOcgAppr\relax + \else + \def\dpsInputOcgAppr{\InputIfFileExists{useocgappr.def}{}{}}% + \fi} +\let\dpsInputOcgAppr\relax +% \end{macrocode} +% \leavevmode\IndexOpt{savedata}\ignorespaces +% When this option is taken, the solution key appears in the footer. If the +% graphicx package is loaded, the answer key is rotated 180 degrees. The +% answer key is always computed and saved in the macro \cs{AnswerKey}. +% The negation of \opt{savedata}, \IndexOpt[\protect\EXCL]{!savedata}\opt{!savedata}, is also +% provided. +% \begin{macrocode} +\DeclareOptionX{savedata}{\savepuzzledatatrue} +\DeclareOptionX{!savedata}{\savepuzzledatafalse} +% \end{macrocode} +% Various switches used by this package +% \begin{macrocode} +\newif\ifwerandomize \werandomizetrue +\newif\ifviewMode \viewModefalse +\newif\ifshowletters\showlettersfalse +\newif\ifshowsolution\showsolutionfalse +\newif\ifsavepuzzledata\savepuzzledatafalse +\newif\ifusebtnappr \usebtnapprfalse +\newif\ifuseocgappr \useocgapprfalse +% \end{macrocode} +% (20/06/03) New default is is \cs{wrtContenttrue}. +% \changes{v1.7}{20/06/03}{Changing from \string\cs{wrtContentfalse} +% as the default to \string\cs{wrtContenttrue} as the default.} +% \begin{macrocode} +\newif\ifwrtContent\wrtContenttrue +% \end{macrocode} +% If a paper option is taken, we show the letters. +% \begin{macrocode} +\ifeqforpaper\showletterstrue\fi +% \end{macrocode} +% \leavevmode\IndexOpt{lang}\ignorespaces +% The only language localizations are the clever commands that appear in the message box. +% We offer two language options, \opt{english} (the default) and \opt{german}. There +% is a custom option for the author to provide his/her own language localizations. +% \begin{macrocode} +\define@choicekey*+{dps.sty}{lang}[\val\nr]{english,german,custom} +{% + \ifcase\nr\relax + \def\dps@lang@type{\input{dps_str_us.def}}\or + \def\dps@lang@type{\input{dps_str_de.def}}\or + \def\dps@lang@type{\input{dps_str_cus.def}}\else + \def\dps@lang@type{\input{dps_str_us.def}}\fi +}{\PackageWarning{dps}{Bad choice for lang, permissible values +are english, german and custom. Try again}} +\def\dps@lang@type{\input{dps_str_us.def}} +% \end{macrocode} +% \begin{macrocode} +\AtEndOfPackage{\dps@lang@type} +\ProcessOptionsX +\edef\dps@restoreCats{% + \catcode`\noexpand\"=\the\catcode`\"\relax + \catcode`\noexpand\,=\the\catcode`\,\relax + \catcode`\noexpand\_=\the\catcode`\_\relax +} +\@makeother\"\@makeother\,\@makeother\_ +% \end{macrocode} +% \section{Required Packages} +% \begin{macrocode} +\RequirePackage{web} +\RequirePackage{eforms} +\ifxetex\makeXasPDOff\fi +\RequirePackage{graphicx} +% \end{macrocode} +% In addition to the \pkg{web} and \pkg{eforms} packages, the following are +% used in the macro package. +% \begin{macrocode} +\RequirePackage{verbatim} +\RequirePackage{calc} +\RequirePackage{multicol} +\RequirePackage{multido} +% \end{macrocode} +% \begin{macrocode} +\hypersetup{pdfencoding=pdfdoc} +% \end{macrocode} +% Input JavaScript for the \opt{usebtnappr} option +% \begin{macrocode} +\ifusebtnappr + \def\x{\AtEndOfPackage{\dpsInputBtnAppr}}% + \expandafter\x\fi +% \end{macrocode} +% Input JavaScript for the \opt{uselayers} option +% \begin{macrocode} +\ifuseocgappr + \def\x{\AtEndOfPackage{\dpsInputOcgAppr}}% +\expandafter\x\fi +% \end{macrocode} +% For \opt{usebtnappr}, we require \pkg{icon-appr} to embed the graphics, +% and make them appearances of buttons. +% \begin{macrocode} +\ifusebtnappr + \def\dps@RP{\RequirePackage{icon-appr}[2020/06/05]} + \expandafter\dps@RP +\fi +% \end{macrocode} +% \changes{v1.7}{20/06/03}{Detect if \string\texttt{icons-pglst.sav}, if yes +% set \string\cs{wrtContentfalse}} +% (20/06/03) If the file \texttt{icons-pglst.sav} is present, that means +% the author has already compiled \texttt{icons.tex}, so we can +% set \cs{wrtContentfalse}. For the \opt{usebtnappr} option: If \cs{ifwrtContent} is true (\texttt{icons.tex} +% has not produced the \texttt{icons-pglst.sav} file yet), we set +% \cs{savepuzzledatatrue}; otherwise, if \cs{ifwrtContent} is false, we set +% \cs{savepuzzledatafalse}. +% \begin{macrocode} +\def\dps@ckForpglst{\IfFileExists{icons-pglst.sav} + {\global\wrtContentfalse}{} + \ifusebtnappr + \ifwrtContent + \global\savepuzzledatatrue + \else + \global\savepuzzledatafalse + \fi + \fi +} +\ifusebtnappr +\def\dps@emitEOP{\AtEndOfPackage{\dps@ckForpglst}} +\expandafter\dps@emitEOP\fi +% \end{macrocode} +% \paragraph*{Input \app{random.tex}.} Input and make modifications. +% \begin{macrocode} +\@ifundefined{nextrandom}{\input{random.tex}}{} +% \end{macrocode} +% We modify \cs{nextrandom} to save the startup seed. +% \begin{macrocode} +\def\dps@nextrandom{% + \def\nextrandom{\begingroup + \ifnum\randomi<\@ne % then initialize with time + \global\randomi\time + \global\multiply\randomi388 \global\advance\randomi\year + \global\multiply\randomi31 \global\advance\randomi\day + \global\multiply\randomi97 \global\advance\randomi\month + \message{Randomizer initialized to \the\randomi.}% + \nextrandom \nextrandom \nextrandom + \xdef\ds@saveRandomSeed{\the\randomi}% + \fi + \count@ii\randomi + \divide\count@ii 127773 % modulus = multiplier * 127773 + 2836 + \count@\count@ii + \multiply\count@ii 127773 + \global\advance\randomi-\count@ii % random mod 127773 + \global\multiply\randomi 16807 + \multiply\count@ 2836 + \global\advance\randomi-\count@ + \ifnum\randomi<\z@ \global\advance\randomi 2147483647\relax\fi + \endgroup + } +} +\newif\ifnextrandomredefd\nextrandomredefdfalse +% \end{macrocode} +% This package modifies \cs{nextrandom} from \pkg{random.tex}; however, +% other package, most notably, also use the \pkg{random.tex} macros and overwrite +% this definition of \cs{nextrandom}. To work around this problem, this package +% delays the redefinition of \cs{nextrandom} until is is first used in the preamble +% The command \cs{redefnextrandomAsNeeded} appears in the \cs{ds@randomizeList}, which +% is where all randomization occurs. +% \begin{macrocode} +\def\redefnextrandomAsNeeded{\ifnextrandomredefd\else + \global\let\nextrandom\dps@nextrandom + \global\nextrandomredefdtrue\fi} +% \end{macrocode} +% \leavevmode\DescribeMacro\useRandomSeed\hskip-\marginparsep +% \texttt{\darg{\ameta{pos-num}}} +% Use the number \ameta{pos-num} as the initial seed. +% \begin{macrocode} +\def\useRandomSeed#1{\randomi=#1 + \def\ds@saveRandomSeed{#1}} +% \end{macrocode} +% With \DescribeMacro\inputRandomSeed\cs{inputRandomSeed}, you input a seed value earlier saved +% with the option savedata. That way, you always get the same seed +% value as you move from the puzzle file to the icons file and back +% again. +% \begin{macrocode} +\def\inputRandomSeed{\ifwerandomize + \InputIfFileExists{\jobname_data.sav}{}{}% + \edef\ds@saveRandomSeed{\the\randomi}\fi} +% \end{macrocode} +% \leavevmode +% \DescribeMacro\useLastSeed\cs{inputRandomSeed} Input a last seed value +% that was available at the end of the last compile. (This assumes \opt{savedata} +% is an active option.) If the SAV file does not exists, the seed used is based +% on the data and time. +% \begin{macrocode} +\def\dpsLastSeed#1{\def\dps@LastSeed{#1}} +\def\useLastSeed{\ifwerandomize + \InputIfFileExists{\jobname_data.sav}{}{}% + \@ifundefined{dps@LastSeed}{} + {\randomi=\dps@LastSeed\relax}% + \edef\ds@saveRandomSeed{\the\randomi}\fi +} +% \end{macrocode} +% +% \section{Switches and things} +% +% \begin{macrocode} +\newif\ifforquestions \forquestionstrue +\newcount\ds@nCnt +\newcount\ds@nMax +\newcount\ds@qNumber\ds@qNumber=0 +\newcount\ds@aNumber\ds@aNumber=0 +\newcount\ds@probCnt \ds@probCnt=0 +\newcount\ds@nCntCols \ds@nCntCols=0 +\newcount\ds@getRanNum +\newtoks\ds@listIn \ds@listIn={} +\newtoks\ds@newListIn \ds@newListIn={} +\newtoks\ds@listOut \ds@listOut={} +\newtoks\ds@tmpToks \ds@tmpToks={} +\newtoks\ds@qlistOut \ds@qlistOut={} +\newtoks\ds@alistOut \ds@alistOut={} +\newtoks\ds@PuzzleAppearancetoks \ds@PuzzleAppearancetoks={} +\newtoks\ds@QuesAppearancetoks \ds@QuesAppearancetoks={} +\newtoks\ds@AnsAppearancetoks \ds@AnsAppearancetoks={} +\newwrite \ds@question@write +\setlength{\multicolsep}{\topsep} +\def\csarg#1#2{\expandafter#1\csname #2\endcsname} +\let\dps@One=1 \let\dps@Zero=0 +% \end{macrocode} +% \section{Building the Puzzle} +% \subsection{Declaring the puzzle} +% \begin{macro}{\DeclarePuzzle}\hskip-\marginparsep\texttt{\darg{\ameta{puzzle-arg}}}, where +% \ameta{puzzle-arg} is a series of \emph{pairs of arguments}. +%\begin{quote}\ttfamily +% \string\DeclarePuzzle\{\%\\ +% \null\quad\darg{\ameta{letter\SUB1}}\darg{\ameta{name\SUB1}}\\ +% \null\quad\darg{\ameta{letter\SUB2}}\darg{\ameta{name\SUB2}}\\ +% \null\quad\dots\\ +% \null\quad\dots\\ +% \null\quad\darg{\ameta{letter\SUB{n}}}\darg{\ameta{name\SUB{n}}}\\ +% \} +%\end{quote} +% The argument \ameta{letter} represents a letter in the puzzle; \ameta{letter} plays two roles: (1) +% it is used to typeset the letters into the document when certain options, such as \opt{viewmode}, are used; +% (2) it is used as the default value of a text fields that is created (when the puzzle is built to be interactive). +% This creates a problem for special characters, such as \"{u}; on one hand the letter is \verb~\"{u}~ (when typeset), +% and is \verb~\string\374~ when placed into a text field (\cs{341}) is the (octal) PDFDocEncoding of u-umlaut. +% The way around this conundrum is to use \cs{texorpdfstring}: use \ameta{letter} to be \verb~{\texorpdfstring{\"{u}}{\string\374}}~. +% +% The second argument pair is \ameta{name}, this is a unique name that is used in the construction of the underlying +% text field name: the name of the field becomes \texttt{puzzle.\ameta{name}}. As a result, \ameta{name} needs to be +% a JavaScript identifier (or, basically consist of letters and numbers). In the case of special characters such as our umlaut problem, we can assign a name like so: +%\begin{Verbatim}[xleftmargin=\parindent,codes={\def\OR{\llap{\rlap{\textsf{or}}\kern\parindent}}\catcode`\%=9},commandchars={!()}] +%\texorpdfstring{\protect\"{u}}{\ifxetex ü\else\string\374\fi}}{uml} +%!OR +%\tops{\protect\"{u}}{\ifxetex ü\else\string\374\fi}}{uml} +%\end{Verbatim} +%where \cs{tops} is an alias for \cs{texorpdfstring}. This argument pair is seen several times in the demonstration files. There are +%two special names, these are \texttt{space} and \texttt{punc}; as a argument pair, these should appear as follows: +%\verb!{}{space}! and \verb~{,}{punc}~, respectively. Spaces and punctuation are not normally part of the puzzle to be discovered +%by answering questions, though they could be. +% +% \begin{macrocode} +\def\DeclarePuzzle#1{% + \gdef\puzzleParameters{#1}% + \let\DPSNamesList\@gobble + \dps@getNames#1\relax\relax +} +\def\dps@getNames{\begingroup\dps@getNames@i} +\def\dps@getNames@i#1#2{% + \ifx#2\relax\let\getNextN@me\endgroup + \else\let\getNextN@me\dps@getNames@i +% \end{macrocode} +% We skip adding to \cs{DPSNamesList} if \texttt{\#2} is \texttt{space}, +% \texttt{punc}, \texttt{cr}, or \texttt{\#2} has already been added. +% \begin{macrocode} + \def\@rgii{#2}\ifx\@rgii\ds@myspace\else + \ifx\@rgii\ds@punc\else + \ifx\@rgii\ds@cr\else + \@ifundefined{ds@name@#2}{\g@addto@macro\DPSNamesList{,"#2"}% + \csarg\let{ds@name@#2}\@empty}{}% + \fi\fi\fi + \fi + \getNextN@me +} +% \end{macrocode} +% \leavevmode\DescribeMacro\nPuzzleCols\hskip-\marginparsep\texttt{\darg{\ameta{nCols}}} +% As a convenience, we provide a way to pass the number of columns for the puzzle to the +% \cs{insertPuzzle\darg{\ameta{nCols}}} command. +% \begin{macrocode} +\def\nPuzzleCols#1{\def\nCols{#1}} +\let\nCols\@empty +% \end{macrocode} +% \subsection{The underlying text fields of the puzzle} +%\leavevmode +% \DescribeMacro{\PuzzleAppearance}\hskip-\marginparsep\texttt{\darg{\ameta{KV-pairs}}} +% The command \cs{PuzzleAppearance} can be used to change the appearance of the text fields for +% the puzzle, where, \ameta{KV-pairs} is a set of \pkg{eforms} key-value pairs. +%\changes{v1.0}{2006/10/31} +%{ +% Added a token list to hold any user changes in the appearance of the puzzle, as +% as suggested by Robert Marik. +%} +% \begin{macrocode} +\def\PuzzleAppearance#1{\ds@PuzzleAppearancetoks={#1}} +% \end{macrocode} +% \leavevmode +% \DescribeMacro\ds@makeTextField\hskip-\marginparsep\texttt{\darg{\ameta{letter}}\darg{\ameta{name}}} +% The command acts on each pair of arguments of the command \cs{DeclarePuzzle}; it either creates +% a text field or an underlined space, depending on the options. Control the width of the fields +% with \DescribeMacro\wdPuzzleFields\cs{wdPuzzleFields\darg{\ameta{width}}} and the height +% with \DescribeMacro\htPuzzleFields\cs{htPuzzleFields\darg{\ameta{height}}}. +% \changes{v1.1}{2020/04/21}{Added \string\cs{wdPuzzleFields} and \string\cs{htPuzzleFields}} +% \begin{macrocode} +\def\wdPuzzleFields#1{\bgroup\setlength\@tempdima{#1}% + \xdef\wd@fPF{\the\@tempdima}\egroup} +\def\wd@fPF{1.6em} +\def\htPuzzleFields#1{\bgroup\setlength\@tempdima{#1}% + \xdef\ht@fPF{\the\@tempdima}\egroup} +\def\ht@fPF{11bp} +\def\dps@strut{\rule{0pt}{\ht@fPF}} +% \end{macrocode} +% The definition of \cs{ds@makeTextField} is a function of the mode the document is in: +% for paper versus view mode. +% \begin{macrocode} +\ifeqforpaper + \ifviewMode + \def\ds@makeTextField#1#2{\def\argii{#2}\ifx\argii + \ds@myspace\let\ds@ul\relax\else\let\ds@ul\underbar\fi + \ifshowletters\raisebox{-10pt}{% + \makebox[0pt][l]{\makebox[\wd@fPF][c]{\footnotesize + \ds@getProbNumber{#1}{#2}}}}\fi + \ds@ul{\makebox[\wd@fPF][c]{\dps@strut + \Hy@pdfstringfalse#1}}} + \else + \def\ds@makeTextField#1#2{\def\argii{#2}\ifx\argii\ds@myspace + \let\ds@ul\relax\else\let\ds@ul\underbar\fi + \ifshowletters\raisebox{-10pt}{% + \makebox[0pt][l]{\makebox[\wd@fPF][c]{\footnotesize + \ds@getProbNumber{#1}{#2}}}}\fi + \ds@ul{\makebox[\wd@fPF][c]{\dps@strut\hfil}}} + \fi +\else + \ifviewMode + \def\ds@makeTextField#1#2{\ifshowletters\raisebox{-10pt}{% + \makebox[0pt][l]{\makebox[\wd@fPF][c]{% + \footnotesize\ds@getProbNumber{#1}{#2}}}}\fi + \underbar{\makebox[\wd@fPF][c]{\dps@strut + \Hy@pdfstringfalse#1}}} + \else + \def\ds@makeTextField#1#2{\ifshowletters + \raisebox{-10pt}{\makebox[0pt][l]{\makebox[\wd@fPF][c]{% + \footnotesize\ds@getProbNumber{#1}{#2}}}}\fi + \edef\textfieldTmp{\noexpand\textField[\noexpand\Q{1}% + \noexpand\S{U}\noexpand\Ff\noexpand\FfReadOnly + \the\ds@PuzzleAppearancetoks\noexpand\DV{#1}]% + {puzzle.#2}{\wd@fPF}{\ht@fPF}}\Hy@pdfstringtrue\textfieldTmp} + \fi +\fi +% \end{macrocode} +% \end{macro} +% Later in this package the \cs{ds@buildAnswerKey} is defined and must be expanded +% at the appropriate moment. The command uses information from all components +% of the puzzle: the puzzle, the questions, and the answers. So, we must wait until +% all components have been typeset. This is the purpose of \cs{dps@emitAK}; its value +% is increased when each component is typeset. When it reaches a value of $4$, it is +% at that time \cs{ds@buildAnswerKey} is expanded. +% \begin{macrocode} +\def\dps@emitAK{0} +\def\dps@AddToEmitAK#1{\bgroup + \@tempcnta=\dps@emitAK\relax + \advance\@tempcnta by#1\relax + \xdef\dps@emitAK{\the\@tempcnta}\egroup +} +\def\dps@ckEmitAK{\ifnum\dps@emitAK>\thr@@\expandafter + \ifshowletters\expandafter\ds@buildAnswerKey\fi\fi} +% \end{macrocode} +% \subsection{Inserting the puzzle into the document} +% \begin{macro}{\insertPuzzle} The command element that inserts the puzzle data that has already +% been declared with \cs{DeclarePuzzle}. +% Use \cs{insertPuzzle} to insert the puzzle at the location desired. The puzzle is placed +% in a tabular environment. The only argument of this command is the number of columns +% you want for this tabular environment. For example, \verb!\insertPuzzle{18}! distributes +% the puzzle so that there are $18$ columns per row, one letter per column. +% \begin{macrocode} +\def\insertPuzzle#1{\begingroup\def\@rgi{#1}% + \ifx\@rgi\@empty + \ifx\nCols\@empty + \PackageWarning{dps}{\string\insertPuzzle\space + needs an argument, use\MessageBreak + either \string\insertPuzzle{<nCols>} or\MessageBreak + declare \string\nPuzzleCols{<nCols>} in preamble.\MessageBreak + Setting <nCols> to 10 for now}\gdef\nCols{10}% + \fi + \else + \xdef\nCols{#1}% + \fi + \ifviewMode\Hy@pdfstringfalse\else\Hy@pdfstringtrue\fi + \let\tops\texorpdfstring\expandafter\dps@Puzzle + \expandafter{\puzzleParameters}\endgroup + \dps@AddToEmitAK{1}\dps@ckEmitAK +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\rowsep} +% This command is used to adjust the space between row of the tabular environment +% for the puzzle. The default is \verb!\rowsep{2ex}!. +% \begin{macrocode} +\def\rowsep#1{\gdef\@rowsep{[#1]}\gdef\@rowskip{#1}} +\rowsep{\rowsep@default} +\def\rowsep@default{2ex} +% \end{macrocode} +% \end{macro} +% This code create the tabular environment, creating a new row when necessary, +% and inserts the text field or typesets the puzzle (in the case of \texttt{viewmode}). +% \changes{v1.1}{2020/04/21}{Replace \string\env{tabular*} with \string\env{tabular} +% in \string\cs{insertPuzzle}} +% \begin{macrocode} +\def\eq@tabSep{&}\def\ds@punc{punc} +% \end{macrocode} +% The command that \cs{insertPuzzle} calls, the argument is the paired +% \texttt{\darg{\ameta{letter}}\allowbreak\darg{\ameta{name}}} data structure. +% We insert \cs{relax}\cs{relax} to identify the end of the data-structure, +% then pass on to \cs{dps@@Puzzle} +% \begin{macrocode} +\def\dps@Puzzle#1{\edef\eq@tabEnd{\noexpand\\\@rowsep}% + \dps@@Puzzle#1\relax\relax}% +% \end{macrocode} +% \cs{dps@@Puzzle} begins a \env{tabular}, then passes the ball +% to \cs{@dpsPuzzlei}. +% \begin{macrocode} +\def\dps@@Puzzle{\begin{tabular} + {@{}*{\nCols}l@{}}\@dpsPuzzlei +} +% \end{macrocode} +% Parse the data structure, taking care to handle \texttt{punc} and \texttt{cr} correctly. +% to \cs{@dpsPuzzlei}. +% \begin{macrocode} +\def\@dpsPuzzlei#1#2{\ifx#2\relax + \gdef\nextPuzzleChar{\@dpsPuzzleDone}\else + \gdef\nextPuzzleChar{\@dpsPuzzleii{#1}{#2}}\fi + \nextPuzzleChar +} +% \end{macrocode} +% We've checked for \cs{relax} and we're OK to continue. The next pair +% may be a special pair, we don't make a field if its a special field +% (\texttt{cr} or \texttt{punc}). +% \changes{v1.6}{2020/05/31}{Improved parsing for \string\texttt{punc} +% and \string\texttt{cr}} +% \begin{macrocode} +\def\@dpsPuzzleii#1#2{\def\argii{#2}% + \ifx\argii\ds@punc + % so something with punc + \def\@puzzNext{#1\@takeaPeek}%\@setSep@dpsPuzzleii}% + \else\ifx\argii\ds@cr + % do something with cr + \def\@puzzNext{\global\ds@nCntCols\z@ + \eq@tabEnd\@dpsPuzzlei}% + \else + % ok to make a field + \def\@puzzNext{\ds@makeTextField{#1}{#2}\@takeaPeek}% + \fi\fi + \@puzzNext +} +\def\ds@cr{cr} +\def\@takeaPeek#1#2{\def\argii{#2}% + \ifx\argii\ds@punc +% \end{macrocode} +% A punctuation can be followed by the \texttt{cr} token, we better check, +% by taking another peek. +% \begin{macrocode} + \def\@puzzNext{#1\@takeaPeek}% + \else +% \end{macrocode} +% We allow a markup to end the tabular line before reaching the number of \cs{nCols}. +% This may be needed when there is an long puzzle, and a \cs{nCols} gives weird +% row breaks. +% \begin{macrocode} + \ifx\argii\ds@cr + \def\@puzzNext{\global\ds@nCntCols\z@ + \eq@tabEnd\@dpsPuzzlei}% + \else + \def\@puzzNext{\@setSep@dpsPuzzleii{#1}{#2}}% + \fi + \fi + \@puzzNext +} +\def\@setSep@dpsPuzzleii{\global\advance\ds@nCntCols\@ne + \ifnum\ds@nCntCols=\nCols\relax + \expandafter\eq@tabEnd + \global\ds@nCntCols\z@\else + \expandafter\eq@tabSep\fi + \@dpsPuzzlei} +\def\@dpsPuzzleDone{\end{tabular}\ifnum\ds@nCntCols=0\relax + \ifshowletters\vskip\@rowskip\relax + \else\vskip3pt\fi + \vskip-2\baselineskip + \fi\kern0pt} +% \end{macrocode} +%\subsection{The answer key} +% \begin{macro}{\AnswerKey} +% The command \cs{AnswerKey} is defined by \cs{ds@buildAnswerKey}, which is expanded +% after all components of the puzzle have been typeset. +% and it (\cs{AnswerKey}) is available thereafter for manual insertion into the document. If the \texttt{showanswerkey} +% option is taken, it is displayed at the bottom of the page. If the \texttt{savedata} +% option is taken, the answer key is save to a file along with the random seed that generated +% this answer key. The file name containing the puzzle data is \cs{jobname\_data.sav}. +% \begin{macrocode} +\def\AnswerKey{The answer key is not available.\PackageWarning{dps} + {The showletters option is required to generate\MessageBreak + an answer key,}} +\def\ds@buildAnswerKey +{% + {% local + \Hy@pdfstringfalse + \let\tops\texorpdfstring + \let\protect\@unexpandable@protect + \count@\z@\toks@={}% + \loop + \advance\count@\@ne + \edef\y{\@nameuse{dps@probLetterii\the\count@}}% + \edef\x{\@nameuse{dps@probLetterKey\y}}% + \expandafter\ifx\x\relax\else + \csarg\xdef{dps@probLetter\the\count@}{\expandafter\noexpand + \csname dps@probLetterAlt\y\endcsname}\fi + \xdef\AnswerKey{\the\toks@ + \the\count@--\@nameuse{dps@probLetter\the\count@}; }% + \toks@=\expandafter{\AnswerKey}% + \ifnum\count@ < \ds@qNumber\repeat + }% + \ifshowsolution + \cfooter{\let\tops\texorpdfstring + \footnotesize\@ifundefined{rotatebox}{\AnswerKey}% + {\rotatebox{180}{\AnswerKey}}}\fi +} +\def\ds@writePuzzleData{\ifsavepuzzledata + \newwrite \ds@savedata + \begingroup + \immediate\openout \ds@savedata \jobname_data.sav + \def\msgi{Initial seed} + \def\msgii{Answer key:} + \let\verbatim@out\ds@savedata + \uccode`c=`\%\uppercase{% + \ifwerandomize + \dps@IWVO{\string\randomi=\ds@saveRandomSeed\space + c \msgi}% + \dps@IWVO{\string\dpsLastSeed{\the\randomi}}\fi + \ifshowletters\let\tops\texorpdfstring + \set@display@protect + \dps@IWVO{c \msgii\space\AnswerKey}\fi + } + \immediate\closeout\ds@savedata + \endgroup +\fi} +\AtEndDocument{\ds@writePuzzleData} +% \end{macrocode} +% \end{macro} +% \leavevmode\DescribeMacro\setdpsfootskip\hskip-\marginparsep\texttt{\darg{\ameta{skip}}} +% When the \opt{showanswerkey} is in force, \cs{AnswerKey} is placed +% in the running footer (\cs{cfooter}) of \pkg{web}. To facilitate the positioning +% of the running footer, we define a convenience command to set \cs{web@footskip} +% used by \pkg{web}. +% \changes{v1.1}{2020/04/21}{Added \string\cs{setdpsfootskip}} +% \begin{macrocode} +\def\setdpsfootskip#1{\bgroup + \setlength\@tempdima{#1}\ifeqforpaper\else + \xdef\web@footskip{\the\@tempdima}\fi + \egroup\InitLayout % a web command +} +\setdpsfootskip{.25in} +% \end{macrocode} +% \subsection{Support for a sideshow} +% A sideshow consists of a tiled graphic that is revealed as the player works the puzzle. +% The techniques used to build a sideshow depends on the options \opt{usebtnappr} and \opt{uselayers}. +% The command \DescribeMacro\randomizePicMappings\cs{randomizePicMappings}, when expanded in the +% preamble, will randomize the order the tiles appear in the slideshow; the default is no randomization. +% \begin{macrocode} +\let\DPSIndxList\@empty +\let\DPSNamesList\@empty +\def\randomizePicMappings{\def\bRandPicMaps{true}} +\def\bRandPicMaps{false} +% \end{macrocode} +% \leavevmode\DescribeMacro\sortPicMappings Pictures are randomly placed in the sideshow +% and the bubble sort is used to sort them out, as a final event when the puzzle is solved. +% This command does nothing if the \opt{usebtnappr} option is not taken; that is, this is a +% feature of the \opt{usebtnappr} option. +% \begin{macrocode} +\ifusebtnappr + \def\sortPicMappings{% + \InputIfFileExists{sortjs.def}{}{}% + \OpenAction{\JS{try{if(!hasBeenRandomized) + {hasBeenRandomized=true;mixupDPS();showDPS();} + }catch(e){}}}% + } +\else + \let\sortPicMappings\relax +\fi +% \end{macrocode} +% \leavevmode\DescribeMacro\sideshowPackaged +% The side show pictures are packaged into a single PDF, the order of the pages are as expected. +% The default is they are not packaged. It is assumed the filename is \texttt{\ameta{basename}\_package.pdf} +% (When in a package, the pictures must be in a PDF file). +% \begin{macrocode} +\newif\if@isPackaged \@isPackagedfalse +\def\sideshowPackaged{\@isPackagedtrue} +% \end{macrocode} +% +% \section{Questions and Answers} +% \begin{environment}{Composing} +% This is the environments in which the composing of questions and answers are made. +% Use the \env{cQ} and \env{cA} for this purpose. +% \begin{macrocode} +\newenvironment{Composing} +{\global\ds@qNumber=0 \global\ds@aNumber=0} +{\aftergroup\ds@publishRandomLists} +% \end{macrocode} +% \end{environment} +% Here are the two environment (\env{cQ} and \env{cA}) for composing questions and answers. The argument +% of each environment corresponds to a form field in the puzzle. Each of these +% environments are verbatim write environments; they write each question and solution +% to a separate \texttt{.cut} file. These individual files are ultimately input +% in a random order. A typical pair of environments looks like these two: +% +% \begin{environment}{cQ} Sets the content of the question. +% \changes{v1.1}{2020/04/21}{Modified \string\textsf{cQ}, using \string\cs{set@display@protect} +% and \string\cs{set@typeset@protect}} +% \begin{macrocode} +\newenvironment{cQ}[1] +{% + \global\advance\ds@qNumber\@ne + \immediate\openout \ds@question@write \jobname_q\the\ds@qNumber.cut + \let\verbatim@out\ds@question@write\set@display@protect + \dps@IWVO{\protect\dpsQ{#1}}% + \set@typeset@protect + \verbatimwrite +}{% + \endverbatimwrite + \immediate\closeout \ds@question@write +} +% \end{macrocode} +% The \env{cA} environment has an optional argument. This optional argument is only used +% when the document is compiled with the showletters option. The value of the argument +% is a letter to appear in the answers column. Normally, first entry of the argument pair +% \texttt{\darg{\ameta{letter}}\darg{\ameta{name}}} of +% \cs{DeclarePuzzle} is used. Cases where you would want to include this optional +% argument are (1) when giving an answer that does not correspond to a question; (2) the +% letter is capitalized, suggesting a proper name or the beginning of a sentence, use the +% optional argument to list the letter in lower case. The latter case is common, for example, +%\begin{verbatim} +% \begin{cQ}{H} +% Who wrote this package? +% \end{cQ} +% \begin{cA}[h]{H} +% D.P. Story +% \end{cA} +%\end{verbatim} +%The capital `H' begins the puzzle, but we don't want the player to see a capital `H' if +%the \opt{showletters} option is taken. +% \begin{environment}{cA} +% Sets the contents of the answer. +% \changes{v1.1}{2020/04/21}{Modified \string\textsf{cA}, using \string\cs{set@display@protect} +% and \string\cs{set@typeset@protect}} +% \begin{macrocode} +\newenvironment{cA}[2][] +{% + \def\argi{#1}\global\advance\ds@aNumber\@ne + \immediate\openout \ds@question@write \jobname_a\the\ds@aNumber.cut + \let\verbatim@out\ds@question@write + \set@display@protect + \dps@IWVO{\protect\dpsA\ifshowletters + \ifx\argi\@empty\else[#1]\fi\fi{#2}}% + \set@typeset@protect + \verbatimwrite} +{% + \endverbatimwrite + \immediate\closeout \ds@question@write +} +% \end{macrocode} +% \end{environment} +% \end{environment} +% \begin{macro}{\QuesAppearance} +% \begin{macro}{\AnsAppearance} +% These two commands can be used to change the appearance of the checkboxes for the questions and answers. +% When the \texttt{forpaper} \textsf{web} option is taken, these have no effect. +% \begin{macrocode} +\def\QuesAppearance#1{\ds@QuesAppearancetoks={#1}} +\def\AnsAppearance#1{\ds@AnsAppearancetoks={#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% The commands \cs{dpsQ} and \cs{dpsA} are the ones that produce the checkboxes, and define the +% JavaScript actions. +% +% The two commands \DescribeMacro\afterQhookA\cs{afterQhookA} and \DescribeMacro\OnFocusQhookAA\cs{OnFocusQhookAA} can be redefined +% for additional JS action, the first is a hook into the mouse up action, and the second is +% a hook to the on focus action. These two can be redefined as needed, but be sure to preserve the JS +% functionality. +% \begin{macrocode} +\def\afterQhookA#1{if(PlayerSignIn());} +%\let\afterQhookA\@gobble +\let\OnFocusQhookAA\@gobble +% \end{macrocode} +%\leavevmode\DescribeMacro\widestFmtdQNum\hskip-\marginparsep\texttt{\darg{\ameta{text}}} +%Sets the width of the underlying checkbox for the question. +% \changes{v1.1}{2020/04/21}{Added \string\cs{widestFmtdNum} to set width of +% the checkbox for questions} +% \begin{macrocode} +\def\widestFmtdQNum#1{\bgroup + \settowidth{\@tempdima}{#1}% + \ifxetex\advance\@tempdima2.5bp\else + \advance\@tempdima.5pt\fi + \xdef\Qwidth{\the\@tempdima}\egroup} +\widestFmtdQNum{00.} +\def\htOfQ#1{\setlength{\@tempdima}{#1}\ifxetex + \advance\@tempdima2bp\relax\fi\edef\Qht{\the\@tempdima}} +\htOfQ{13bp} +% \end{macrocode} +% Set the checkboxes and JS action for questions. Allow also, changes to appearance +% through the \cs{QuesAppearance} command. +% \begin{macro}{\dpsQ} +% Sets the checkbox and content of a question. +% \begin{macrocode} +\newcommand{\dpsQ}[1]{\item\relax\ifeqforpaper\else + \edef\checkboxTmp{\noexpand\checkBox[\the\ds@QuesAppearancetoks + \noexpand\textSize{0}\noexpand + \A{\noexpand\JS{activeQuestion = event.target.name;\noexpand + \r clearRedCrosses();\noexpand\r\noexpand\afterQhookA{#1}}}% + \noexpand\AA{\noexpand\AAOnFocus{\noexpand\JS{% + this.resetForm(["ckbxQ"]);\noexpand\r\noexpand + \OnFocusQhookAA{#1}}}}]{ckbxQ.#1}{\Qwidth}{\Qht}{Yes}}% + \makebox[0pt][r]{\strut + \smash{\checkboxTmp}\efKern{-.5pt}{-1.5pt}\enspace}\fi + \ignorespaces +} +% \end{macrocode} +% Set the checkboxes and JS action for answers. Allow also, changes to appearance +% through the \cs{AnsAppearance} command. This command obeys the \texttt{showanswerlabels} +% option by re-defining the command \cs{dpsAitemOptArg}. The default definition +% is \verb!\def\dpsAitemOptArg{[]}!, which cancels the display of the item labels. +% \changes{v1.1}{2020/04/21}{Added \string\cs{ltrFmtA} to format the answer letter} +% \begin{macrocode} +% \end{macrocode} +% \leavevmode\DescribeMacro\ltrFmtA\hskip-\marginparsep\texttt{\darg{\ameta{fmt-cmds}}} +% When the \opt{showletters} option is in effect, the letters appear amongst the answers. +% the letters may be formatted through \cs{ltrFmtA}. The symbolic \texttt{\#1} represents +% the letter to be formatted; eg, \verb~\ltrFmtA{\textbf{#1}}~ give letters in bold. +% The default is no formatting. +% \begin{macrocode} +\def\ltrFmtA#1{\def\@ltrFmtA##1{#1}} +\ltrFmtA{#1} +% \end{macrocode} +% \leavevmode\DescribeMacro\widestFmtdALtr\hskip-\marginparsep\texttt{\darg{\ameta{text}}} +% Sets the width of the checkbox around the letter. There is a built in with of 8pt. +% \begin{macrocode} +\def\widestFmtdALtr#1{\bgroup + \settowidth{\@tempdima}{#1}\ifxetex + \addtolength{\@tempdima}{2bp+8pt}\else + \addtolength{\@tempdima}{8pt}\fi + \xdef\Awidth{\the\@tempdima}\egroup} +\widestFmtdALtr{w} +\def\htOfA#1{\setlength{\@tempdima}{#1}\ifxetex + \advance\@tempdima2bp\relax\fi\edef\Aht{\the\@tempdima}} +\htOfA{13bp} +% \end{macrocode} +% \begin{macro}{\dpsA} +% Checkbox for the answer. +% \begin{macrocode} +\newcommand{\dpsA}[2][]{\expandafter + \item\dpsAitemOptArg\relax + \ifeqforpaper\else + \edef\checkboxTmp{\noexpand + \checkBox[\the\ds@AnsAppearancetoks + \noexpand\textSize{0}\noexpand + \A{\noexpand\JS{processChoice("#2");}}]% + {ckbxA.#2}{\Awidth}{\Aht}{Yes}}% + \makebox[0pt][r]{\strut + \smash{\checkboxTmp}\enspace}% + \fi + \def\argi{#1}% + \bgroup % dps + \let\tops\texorpdfstring + \Hy@pdfstringfalse + \ifx\argi\@empty + \global\csarg\let{dps@probLetterKey#2}\relax + \else + \csarg\gdef{dps@probLetterKey#2}{#2}% + \csarg\gdef{dps@probLetterAlt#2}{#1}% + \fi + \egroup + \ifshowletters + \ifx\argi\@empty + \let\getLetterNext\relax + \let\ds@foundLetter\dps@Zero\def\ds@currFN{#2}% + \def\getLetterNext{\ds@typesetPuzzleLetter}% + \expandafter\getLetterNext + \else + \makebox[0pt][r]{\let\tops\texorpdfstring + \Hy@pdfstringfalse\@ltrFmtA{#1}\enspace\kern4bp}% + \fi + \fi + \ignorespaces +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macrocode} +\def\ds@typesetPuzzleLetter{\expandafter + \typeset@PuzzleLetter\expandafter{\puzzleParameters}} +\def\typeset@PuzzleLetter#1{\typeset@@PuzzleLetter#1\relax\relax}% +\def\typeset@@PuzzleLetter#1#2{% + \ifx#1\relax + \gdef\nextPuzzleLetter{\relax}\else + \gdef\nextPuzzleLetter{\typeset@PuzzleLetteri{#1}{#2}}\fi + \nextPuzzleLetter +} +\def\typeset@PuzzleLetteri#1#2{\def\argii{#2}\ifx\argii\ds@currFN + \ifx\ds@foundLetter\dps@Zero + \makebox[0pt][r]{\let\tops\texorpdfstring + \Hy@pdfstringfalse\@ltrFmtA{#1}\enspace\kern4bp}% + \let\ds@foundLetter\dps@One\fi + \expandafter\typeset@@PuzzleLetter + \else + \expandafter\typeset@@PuzzleLetter + \fi +} +% \end{macrocode} +% This command is called at \verb!\end{Composing}!, which, in turn, calls +% the macros \cs{ds@randomizeQuestionList} and \cs{ds@randomizeAnswerList} which randomly +% permutes the \verb!1, 2, ... \the\ds@qNumber! and \verb!1, 2, ... \the\ds@aNumber!, +% where \cs{ds@qNumber} and \cs{ds@aNumber} are the number of questions and answers, +% respectively. +% \begin{macrocode} +\def\ds@publishRandomLists{% + \ds@randomizeQuestionList{\the\ds@qNumber}% + \ds@randomizeAnswerList{\the\ds@aNumber}% +} +\def\ds@myspace{space} +\def\ds@getProbNumber#1#2{% + \gdef\ds@currentArgi{#1}\gdef\ds@currentArgii{#2}% + \ifx\ds@currentArgii\ds@myspace\def\ds@probNumNext{\relax}\else + \def\ds@probNumNext{% + \@ifundefined{dps@probNum#2}{\global\advance\ds@probCnt\@ne + \ds@@getProbNumber{\the\ds@probCnt}} + {\csname dps@probNum#2\endcsname}% + }% + \fi + \ds@probNumNext +} +\def\ds@@getProbNumber#1{% + {\count@\z@ \let\\=\ds@getNthOne\the\ds@qlistOut}% + \csname dps@probNum\ds@currentArgii\endcsname +} +\def\ds@getNthOne#1{\advance\count@\@ne + \ifnum\ds@probCnt=#1\relax + \csarg\xdef{dps@probNum\ds@currentArgii}{\the\count@}% + \toks@=\expandafter{\ds@currentArgi}% dps + \csarg\xdef{dps@probLetter\the\count@}{\the\toks@}% dps + \csarg\xdef{dps@probLetterii\the\count@}% + {\ds@currentArgii}% + \fi +} +% \end{macrocode} +% \begin{macro}{\writeComposingEnv} +% This is a helper macro. After you declare your puzzle, \cs{DeclarePuzzle}, +% you can place this command just after, if needed, like so +%\begin{verbatim} +%\writeComposingEnv +%\end{verbatim} +%In the case where \cs{DeclarePuzzle} is in the preamble; above, we begin the doc +% and end the doc; assuming you have not developed your questions yet. The command +% writes to the file \cs{jobname\_comp.def}. This file will be a skeleton of your +% Composing environment, with correct labeling. Copy and paste it into your document +% in some appropriate location, and begin writing your questions. +% \changes{v1.1}{2020/04/21}{\string\cs{writeComposingEnv} no longer needs to be +% followed by begin and end document} +% \begin{macrocode} +\def\writeComposingEnv{% + \newwrite \ds@composing@write + \immediate\openout \ds@composing@write \jobname_comp.def + \let\verbatim@out\ds@composing@write + \dps@IWVO{\string\begin{Composing}}% + \dps@IWVO{}% + \expandafter\write@ComposingEnv\expandafter{\puzzleParameters}% +} +\def\write@ComposingEnv#1{\write@@ComposingEnv#1\relax\relax}% +\newcommand{\ComposingEnvMsg}{\begin{quote}An outline of your + \texttt{Composing}environment is written to + \texttt{\jobname\_comp.def}, based on data in the + argument of your \texttt{\string\DeclarePuzzle} command. Copy and + paste the contents of this file into your puzzle document following + \texttt{\string\DeclarePuzzle} then fill in your questions and + answers. Good luck.\end{quote}} +\def\write@@ComposingEnv#1#2{\ifx#1\relax + \gdef\nextPuzzlePair{% + \dps@IWVO{\string\end{Composing}}% + \immediate\closeout \ds@composing@write}% + \begin{document} + \ComposingEnvMsg + \end{document} + \else\gdef\nextPuzzlePair{\write@@@ComposingEnv{#1}{#2}}\fi + \nextPuzzlePair}% +\def\write@@@ComposingEnv#1#2{% + \gdef\ds@currentArgi{#1}\gdef\ds@currentArgii{#2}% + \ifx\ds@currentArgii\ds@myspace + \def\ds@probNumNext{\write@@ComposingEnv}% + \else + \ifx\ds@currentArgii\ds@punc + \def\ds@probNumNext{\write@@ComposingEnv}\else + \def\ds@probNumNext{% + \@ifundefined{dps@compQ#2}{% write to file + \expandafter\gdef\csname dps@compQ#2\endcsname{found}% + \dps@IWVO{\string\begin{cQ}{\noexpand#1}}% + \dps@IWVO{\string\end{cQ}}% + \dps@IWVO{\string\begin{cA}{\noexpand#1}}% + \dps@IWVO{\string\end{cA}}% + \dps@IWVO{}% + }{}% + \write@@ComposingEnv + }% + \fi + \fi + \ds@probNumNext +} +% \end{macrocode} +% \end{macro} +% A standard \cs{verbatim} write used in exerquiz and other package in the AeB family. +% \begin{macrocode} +\def\verbatimwrite{\@bsphack + \let\do\@makeother\dospecials + \catcode`\^^M\active \catcode`\^^I=12 + \def\verbatim@processline{% + \immediate\write\verbatim@out + {\the\verbatim@line}}% + \verbatim@start} +\def\endverbatimwrite{\@esphack} +\def\dps@IWVO{\immediate\write\verbatim@out} +% \end{macrocode} +% \cs{ds@populateList} is a utility command, its argument is a positive integer, \texttt{n}, +% and it generates a list of the form \verb!\\{1}\\{2}...\\{n}!. This listing is later +% randomly permuted by \cs{ds@randomizeQuestionList} and \cs{ds@randomizeAnswerList}. +% \begin{macrocode} +\def\ds@populateList#1{% + \ds@listIn={}% + \ds@nCnt\z@ + \@whilenum \ds@nCnt < #1\do {% + \advance\ds@nCnt\@ne + \edef\ds@listInHold{\the\ds@listIn\noexpand\\{\the\ds@nCnt}}% + \ds@listIn = \expandafter{\ds@listInHold}% + }% +} +% \end{macrocode} +% Used in \cs{ds@randomizeList} to build the permuted list of numbers. +% \begin{macrocode} +\def\ds@processi#1{\advance\ds@nCnt\@ne + \ifnum\ds@nCnt=\ds@getRanNum\edef\ds@listOutHold{\the\ds@listOut}% + \global\ds@listOut=\expandafter{\ds@listOutHold\\{#1}}% + \else + \edef\ds@listInHold{\the\ds@newListIn}% + \ds@tmpToks = \expandafter{\ds@listInHold\\{#1}}% + \ds@newListIn = \expandafter{\the\ds@tmpToks}% + \fi +} +% \end{macrocode} +% Used in \cs{displayRandomizedQuestions} to input the questions. +% \begin{macrocode} +\def\ds@processii#1{\input{\jobname_q#1.cut}} +% \end{macrocode} +% Used in \cs{displayRandomizedAnswers} to input the answers. +% \begin{macrocode} +\def\ds@processiii#1{\input{\jobname_a#1.cut}} +% \end{macrocode} +% Used in \cs{displayRandomizedAnswersLeftPanel} to input the top half +% of the permuted list. +% \begin{macrocode} +\def\ds@processL#1{\advance\count@\@ne + \ifnum\count@>\ds@aNumber\relax\else\input{\jobname_a#1.cut}\fi} +% \end{macrocode} +% Used in \cs{displayRandomizedAnswersRightPanel} to input the bottom half +% of the permuted list. +% \begin{macrocode} +\def\ds@processR#1{\advance\count@\@ne + \ifnum\count@>\ds@aNumber\relax\input{\jobname_a#1.cut}\fi} +% \end{macrocode} +% \begin{macro}{\displayRandomizedQuestions} +% \begin{macro}{\displayRandomizedAnswers} +% \begin{macro}{\displayRandomizedAnswersLeftPanel} +% \begin{macro}{\displayRandomizedAnswersRightPanel} +% These are user commands that actually display the randomized questions +% and answers. +% \begin{macrocode} +\def\displayRandomizedQuestions{\let\\=\ds@processii\the\ds@qlistOut + \dps@AddToEmitAK{1}\dps@ckEmitAK} +\def\displayRandomizedAnswers{\set@typeset@protect + \let\\=\ds@processiii\the\ds@alistOut + \dps@AddToEmitAK{2}\dps@ckEmitAK} % dps +\def\displayRandomizedAnswersLeftPanel{{\set@typeset@protect + \let\\=\ds@processL\count@\z@ + \divide\ds@aNumber\tw@ \xdef\lastOnLeft{\the\ds@aNumber}% + \the\ds@alistOut}% + \dps@AddToEmitAK{1}\dps@ckEmitAK} +\def\displayRandomizedAnswersRightPanel{{\set@typeset@protect + \let\\=\ds@processR\count@\z@ + \divide\ds@aNumber\tw@ \the\ds@alistOut}% + \dps@AddToEmitAK{1}\dps@ckEmitAK} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% Develop a random permuted list for the questions. +% \begin{macrocode} +\def\ds@randomizeQuestionList#1{% + \global\ds@listIn={}\global\ds@newListIn={}\global\ds@listOut={}% + \global\ds@tmpToks={}%\global\ds@qlistOut={}\global\ds@alistOut={}% + \ds@nMax=#1\relax\ds@populateList{\the\ds@nMax}% + \global\forquestionstrue + \ifwerandomize + \expandafter\ds@randomizeList + \else + \global\ds@qlistOut=\expandafter{\the\ds@listIn} + \fi +} +% \end{macrocode} +% Develop a random permuted list for the answers. Note that \cs{ifwerandomize} +% we randomize, else, the output list is the same as the input list. +% \begin{macrocode} +\def\ds@randomizeAnswerList#1{% + \global\ds@listIn={}\global\ds@newListIn={}\global\ds@listOut={}% + \global\ds@tmpToks={}%\global\ds@qlistOut={}\global\ds@alistOut={}% + \ds@nMax=#1\relax\ds@populateList{\the\ds@nMax}% + \global\forquestionsfalse + \ifwerandomize + \expandafter\ds@randomizeList + \else + \global\ds@alistOut=\expandafter{\the\ds@listIn}% + \fi +} +% \end{macrocode} +% The loop that does all the work for randomizing. +% \begin{macrocode} +\def\ds@randomizeList{\redefnextrandomAsNeeded + \let\\=\ds@processi + \setrannum{\ds@getRanNum}{1}{\ds@nMax}% + \ds@nCnt\z@ +%\typeout{LISTING: \the\ds@listIn}% + \the\ds@listIn + \ds@loopTest +} +% \end{macrocode} +% The loop that does all the work for randomizing. +% \begin{macrocode} +\def\ds@loopTest{\advance\ds@nMax\m@ne\relax + \ifnum\ds@nMax>\z@ + \def\@next{% + \ds@listIn=\expandafter{\the\ds@newListIn}% + \ds@newListIn={}\ds@randomizeList}% + \else + \let\@next\relax + \ifforquestions + \global\ds@qlistOut=\expandafter{\the\ds@listOut}% +%\typeout{\ds@qlistOut = \the\ds@qlistOut}% + \else + \global\ds@alistOut=\expandafter{\the\ds@listOut}% +%\typeout{\ds@alistOut = \the\ds@alistOut}% + \fi + \fi + \@next +} +% \end{macrocode} +% \begin{macro}{\placeMessageField} +% The command inserts the required message field. The optional +% first parameters enables the author to change the appearance +% of the field, the second two required arguments are the width +% and the height of the text field. +% \begin{macrocode} +\newcommand{\placeMessageField}[3][]{\ifeqforpaper\else + \textField[\Ff\FfReadOnly\BC{}#1 + \Ff\FfMultiline]{report}{#2}{#3}\fi} +% \end{macrocode} +% \end{macro} +% \section{Miscellaneous Settings} +% \begin{macro}{\threshold} +% \begin{macro}{\penaltypoints} +% \begin{macro}{\passing} +% Threshold for number of incorrect answers for trying to answer one question. +% If the threshold is exceeded, \cs{dspenaltypoints} are added to the final +% points. Passing is missing no more than \cs{dspassing}. +% \begin{macrocode} +\newcommand{\threshold}[1]{\def\dsthreshold{#1}} +\threshold{3} +\newcommand{\penaltypoints}[1]{\def\dspenaltypoints{#1}} +\penaltypoints{3} +\newcommand{\passing}[1]{\def\dspassing{#1}} +\passing{4} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \section{Advanced features} +% +% One problem when building an interactive puzzle is the lack of space for a rather long +% or complex question. All of the standard designs leave little space for the questions. +% Over the years, I've developed two methods to create more space for asking questions: +% (1) Place the questions in push button appearances; (2) Place the questions in layers +% (ocgs). In this section we provide define some basic commands to make if ``easy'' to +% ask longer question using either of these two methods. +% \subsection{Icon button appearances} +% In this case, in some central region we create a series of push buttons, all of which are initialy +% hidden. Push button can have an icon (a graphic) for its appearance. As the student +% works through the puzzle, the buttons are made visible to pose the question. The question +% is hidden again as the student moves on to the next question. +% +% For this solution, two files are required: (1) the main puzzle file; and (2) an ``icon'' file. +% The next two subsections include commands and environments for each of these two files. +% +% To use the icon button approach, the \IndexOpt{usebtnappr}\opt{usebtnappr} must be specified; in this case the +% package \pkg{icon-appr} in input by this package. +% +% \paragraph*{Workflow:} Creating a finished puzzle is a three step process: +% \begin{enumerate} +% \item Compile the puzzle file with the option \IndexOpt{wrtContent}\opt{wrtContent} +% \item Compile the \texttt{icons.tex} file to create one or more +% icons files +% \item Compile the puzzle file with the option \IndexOpt[\protect\EXCL]{!wrtContent}\opt{!wrtConent} +% \end{enumerate} +% +% \subsubsection{Macros for the main puzzle document} +% +% \begin{macrocode} +%<*btnadv> +% \end{macrocode} +% \begin{environment}{setContent}\hskip-\marginparsep\texttt{\darg{\ameta{name}}} +% (Where \ameta{name} is the second argument of the \cs{DeclarePuzzle} data structure.) +% An environment to set content of the question. The contents of the \env{setContent} +% is written verbatim to the file \cs{jobname-sc(\cs{theenumi}).cut}. This obviously +% assumes the list of questions is in an \texttt{enumerate} environment. These individual +% files are compiled together (in the \texttt{icons.tex} file to a PDF of all the questions. +% The formatting command \DescribeMacro\quesNumTxt\cs{quesNumTxt} is used to format the +% question header; the default is \textbf{Problem \ameta{num}}. Additionally, +% \DescribeMacro\quesNumTxTPost\cs{quesNumTxTPost} that expands immediatelly +% after \cs{quesNumTxt}. +% \goodbreak +% \begin{macrocode} +\newcommand{\quesNumTxt}[1]{\protect\textbf{Problem #1}} +\newcommand{\quesNumTxTPost}{\protect\newline} +\newenvironment{setContent}[1]{% + \immediate\write\@auxout{\string\csarg + \string\xdef{ltrpg#1}{\theenumi}}% + \ifwrtContent + \def\CommentCutFile{\jobname-sc(\theenumi).cut}% + \immediate\openout\CommentStream=\CommentCutFile + \begingroup + \set@display@protect + \let\verbatim@out\CommentStream + \dps@IWVO{\quesNumTxt{\theenumi}\quesNumTxTPost}% + \set@typeset@protect + \expandafter\verbatimwrite + \else + \edef\x{\noexpand\pl@ceQues{\theenumi}}\x\expandafter + \comment + \fi +}{\ifwrtContent\expandafter + \endverbatimwrite + \endgroup + \immediate\closeout\CommentStream + \else + \expandafter\endcomment + \fi +} +% \end{macrocode} +% \leavevmode\DescribeMacro\ltrToNum\hskip-\marginparsep\texttt{\darg{\ameta{num}}} +% The \env{setContent} environment above defines a series of commands that +% associate with each \ameta{name}, the corresponding problem number (\ameta{num}). +% \begin{macrocode} +\def\ltrToNum#1{\@nameuse{ltrpg#1}} +% \end{macrocode} +% \end{environment} +% \paragraph*{Embedding commands}\leavevmode\par\medskip\noindent +% \DescribeMacro{\dpsEmbedIcons} After creating the CUT files, as described in the +% previous environment, we need to compile the CUT files into one or more PDF(s). +% This is done in the other \texttt{icon.tex} file, described below. +% The \cs{dpsEmbedIcons} command goes within the \env{embedding} environment +%\begin{verbatim} +% \begin{embedding} +% \dpsEmbedIcons +% \end{embedding} +%\end{verbatim} +%The \env{embedding} environment is defined in the \pkg{icon-appr} package. +% \cs{dpsEmbedIcons} embeds icons images into the puzzle document. +% \begin{macrocode} +\def\pglstWarningMsg{\PackageWarningNoLine{dps} + {The file icons-pglst.sav not found.\MessageBreak + Icons may not appear. Build the\MessageBreak icons.tex file}} +\ifwerandomize\else\let\pglstWarningMsg\@empty\fi +\def\dpsEmbedIcons{% +\InputIfFileExists{icons-pglst.sav}{\wrtContentfalse} + {\pglstWarningMsg\def\pagelist{}}% + \edef\TFOR{\noexpand\@tfor\noexpand\n:=\pagelist}% + \ifxetex + \TFOR\do{\embedIcon[name=Q\n]{icons-\n.pdf}}% + \else\ifpdf + \TFOR\do{\embedIcon[name=Q\n,hyopts={page=\n}]{icons.pdf}}% + \else % pdfmark + \TFOR\do{\embedIcon[name=Q\n,placement=btnQ.\n,% + page={\n-1}]{icons.pdf}}% + \fi\fi +} +% \end{macrocode} +% \paragraph*{Icon button fields}\leavevmode\par\medskip\noindent +% \DescribeMacro\dpsQuesIcon\hskip-\marginparsep\texttt +% {[\ameta{opts}]\darg{\ameta{num}}\darg{\ameta{wd}}\darg{\ameta{ht}}} The command +% that create a push button with an icon appearance. The \ameta{num} is the question number. +% The field name is \verb~"btnQ.~\ameta{num}\texttt"; the value of the \cs{I} key is an indirect +% reference to the embedding of the image to be use, the reference is \texttt{Q\ameta{num}}. +% \begin{macrocode} +\newcommand{\dpsQuesIcon}[4][]{% + \pushButton[\Ff{\FfReadOnly}\BG{}\S{S}#1\TP{1}\F{\FHidden} + \I{\csOf{Q#2}}\PA{.5 1}]{btnQ.#2}{#3}{#4}} +% \end{macrocode} +%\leavevmode\DescribeMacro\dpsOtherIcon\hskip-\marginparsep\texttt +% {[\ameta{opts}]\darg{\ameta{fieldname}}\darg{\ameta{wd}}\darg{\ameta{ht}}} +% There is allowance for displaying additional button images. The +% \begin{macrocode} +\newcommand{\dpsOtherIcon}[4][]{% \I{\csOf{name}} required + \pushButton[\Ff{\FfReadOnly}\BG{}\S{S}#1\TP{1}\F{\FHidden} + \PA{.5 1}]{#2}{#3}{#4}} +% \end{macrocode} +% \paragraph*{Placing the button icons.} There are several ways of placing +% the image buttons; I have use both the \pkg{textpos} and the \pkg{eso-pic} +% packages, lately, I've preferred the latter package. Examples of both are contained +% in the examples. +% \begin{macrocode} +% \end{macrocode} +% \leavevmode\DescribeMacro\placeQuesIcon\hskip-\marginparsep\texttt{\darg{\ameta{place \cs{dpsQuesIcon}}}} +% We illustrate +%\begin{verbatim} +% \placeQuesIcon{\AddToShipoutPictureFG*{\AtTextCenter{\put(-72,0) +% {\dpsQuesIcon{#1}{2.25in}{9\baselineskip}}}}} +%\end{verbatim} +%using the \pkg{eso-pic} package. The argument \texttt{\#1} is eventually +%the problem number. \cs{placeQuesIcon} defines a macro \cs{pl@ceQues}, which appears +%in the \DescribeEnv{setContent}\env{setContent} environment above. +% \begin{macrocode} +\long\def\placeQuesIcon#1{\@ifundefined{textblock} + {\let\dps@mode\relax}{\let\dps@mode\par}% + \def\pl@ceQues##1{\dps@mode #1}} +% \end{macrocode} +% \DescribeMacro\placeOtherIcon\hskip-\marginparsep\texttt{\darg{\ameta{place \cs{dpsOtherIcon}}}} +% Places an image other than a question. +%\begin{verbatim} +% \placeOtherIcon{\AddToShipoutPictureFG*{\AtTextCenter{\put(-72,0) +% {\dpsOtherIcon[\I{\csOf{Emoji}}]{btnEmoji}{2.25in}{9\baselineskip}}}}} +%\end{verbatim} +%Both of the above examples are from \texttt{examples/advanced/stat\_match1.tex}. +% \begin{macrocode} +\long\def\placeOtherIcon#1{#1} +% \end{macrocode} +% Define hooks into the question checkbox event. +% The two commands \cs{afterQhookA} and \cs{OnFocusQhookAA} are hooks onto +% the \cs{dpsQ} command. This allows us to post process +% the user's choice of a questions, and allows us to execute JS on focus. +% \begin{macrocode} +\def\afterQhookA#1{% + if(!event.target.isBoxChecked(0))dpsHideQFields();\r + else\pdfSP if(PlayerSignIn())dpsShowQues("\ltrToNum{#1}");} +\def\OnFocusQhookAA#1{dpsHidePreviousQues("\ltrToNum{#1}")} +% \end{macrocode} +% \paragraph*{Support for a sideshow} A sideshow is a tiled picture that is +% revealed as the player solves the puzzle. +% +% \subparagraph*{Embedding sideshow graphics}\leavevmode\vskip3pt\noindent +% \DescribeMacro\dpsEmbedSideShow\hskip-\marginparsep\texttt{[\ameta{ext}]\darg{\ameta{n-pics}}\darg{\ameta{path}}} +% We take a graphic and explode it into rows and columns, \ameta{n-pics} is the total number +% of tiled pictures. We assume the tiles are created row-wise. We assume also a naming convention +% for the tiles if \texttt{mypic} is the basename of the picture or graphic, then the tiles are +% named \texttt{mypic\_01}, \texttt{mypic\_02}, \texttt{mypic\_03}, \dots. It is assumed a single digit +% index has a leading 0. Use the command \DescribeMacro\sideshowPackaged +% \cs{sideshowPackaged} prior to \cs{dpsEmbedSideShow}. +% \changes{v1.5}{2020/08/06}{Support for packaged sideshow graphics} +% \begin{macrocode} +\newcommand{\dpsEmbedSideShow}[3][]{\begingroup +% \def\dps@NumSideShowPics{#2}% + \gdef\dpsNumSideShowPics{#2}% + \def\@Ext{#1}\ifx\@Ext\@empty\def\@Ext{.pdf}\else\def\@Ext{.#1}\fi + \@tempcnta\z@ + \let\@embedList\@empty + \let\DPSIndxList\@gobble + \@whilenum \@tempcnta < \dpsNumSideShowPics \do{% + \ds@nCnt\@tempcnta \advance\ds@nCnt\@ne + \ifnum\ds@nCnt<10 \edef\x{0\the\ds@nCnt}\else + \edef\x{\the\ds@nCnt}\fi + \edef\z{\noexpand\g@addto@macro\noexpand\DPSIndxList{,"\x"}}\z + \ifxetex\if@isPackaged + \PackageWarning{dps} + {There is no support for embedding packaged\MessageBreak + PDFs with xelatex. Ignoring the \string\isPackaged\MessageBreak + command}% + \@isPackagedfalse + \fi\fi + \if@isPackaged + \ifpdf + \edef\y{\noexpand + \embedIcon[name=pic\x,% + hyopts={page=\x}]{#3_package.pdf}}% + \else + \edef\y{\noexpand + \embedIcon[name=pic\x,placement=btnpic.\x,% + page=\x-1]{#3_package.pdf}}% + \fi + \else + \edef\y{\noexpand + \embedIcon[name=pic\x,placement=btnpic.\x]{#3_\x\@Ext}}% + \fi + \expandafter\g@addto@macro\expandafter\@embedList\expandafter{\y}% + \@tempcnta\ds@nCnt + }% do + \toks@=\expandafter{\@embedList}\the\toks@ + \endgroup +} +% \end{macrocode} +% \subparagraph*{Inserting sideshow graphics}\leavevmode\vskip3pt\noindent +% \DescribeMacro\insertSideshow\hskip-\marginparsep +% \texttt{\darg{\ameta{rows}}\darg{\ameta{cols}}\darg{\ameta{wd}}\darg{\ameta{ht}}} +% Command for placing the tiles of a picture. We assume that the pictures are number +% consecutively across rows. +% \begin{quote} +% \begin{description} +% \item[\ameta{rows}] the number of rows +% \item[\ameta{cols}] the number of columns +% \item[\ameta{wd}] the width of a tile +% \item[\ameta{ht}] the height of a tile +% \end{description} +% \end{quote} +% \leavevmode\DescribeMacro\tileKVs\hskip-\marginparsep\texttt{\ameta{KV-pairs}} +% A way to pass \pkg{eform} key-values to the optional +% argument of the underlying push button. +% \begin{macrocode} +\def\tileKVs#1{\def\tile@KVs{#1}} +\tileKVs{} +\newcommand\insertSideshow[4]{\begingroup + \offinterlineskip\@tempcnta\z@ + \multido{\iR=1+1}{#1}{\hbox{% + \multido{\iC=1+1}{#2}{% + \global\advance\@tempcnta\@ne + \ifnum\@tempcnta<10\relax + \edef\x{0\the\@tempcnta}\else + \edef\x{0\the\@tempcnta}\fi + \edef\iconPresets{\noexpand\I{\noexpand\csOf{pic\x}}}% + \dpsOtherIcon[\BC{}\FB{true}\presets{\iconPresets} + \presets{\tile@KVs}]{btnpic.\x}{#3}{#4}% + }% inner multido + }}% hbox, outer multido + \endgroup +} +% \end{macrocode} +% \begin{macrocode} +%</btnadv> +% \end{macrocode} +% \subsubsection{Macros for the icon document} +% The icon document is separate from the puzzle document, so we need to create +% a special package (\marginpar{\small\raggedleft\pkg{icon-doc} package}\pkg{icon-doc}) for it. +% \begin{macrocode} +%<*icondoc> +\NeedsTeXFormat{LaTeX2e}[1997/12/01] +\ProvidesPackage{icon-doc} + [2020/04/21 v1.0 icon-doc: + Build Icon file and explode same (dps)] +\newif\ifdpsuseacrobat \dpsuseacrobatfalse +% \end{macrocode} +% The \pkg{icon-doc} package\marginpar{\small\raggedleft\app{xelatex} author} has one option (and one convenience option). +% Both options are targeted at users of \app{xelatex}. +% If the \app{xelatex} has \app{Acrobat} then use the \IndexOpt{useacrobat}\opt{useacrobat} option; otherwise, use +% use the \IndexOpt[\protect\EXCL]{!useacrobat}\opt{!useacrobat} option. The default is \opt{!useacrobat} so this option need not appear in the option list. +% More on the problems of \app{xelatex} in the description of \cs{@MultiQuesFiles} below. +% \begin{macrocode} +\DeclareOption{useacrobat}{\dpsuseacrobattrue} +\DeclareOption{!useacrobat}{\dpsuseacrobatfalse} +\DeclareOption{twice}{\dpscomptwicetrue} +\newif\ifdpscomptwice \dpscomptwicefalse +\ProcessOptions\relax +\RequirePackage{ifxetex} +\RequirePackage{shellesc} +\RequirePackage{web} +\RequirePackage{eforms} +\execJSOn +\pagestyle{empty} +\parindent0pt \parskip0pt +\newwrite \wrtPkg +\newwrite\wrticonbody +\def\IWB#1{\immediate\write\wrticonbody{#1}} +\def\IWP#1{\immediate\write\wrtPkg{#1}} +% \end{macrocode} +% Some standard code for writing verbatim to a file. +% \begin{macrocode} +\def\verbatimwrite{\@bsphack + \let\do\@makeother\dospecials + \catcode`\^^M\active \catcode`\^^I=12 + \def\verbatim@processline{% + \immediate\write\verbatim@out + {\the\verbatim@line}}% + \verbatim@start} +\def\endverbatimwrite{\@esphack} +% \end{macrocode} +% \begin{environment}{icondoc} +% Through the \env{icondoc} environment, you can set the {\LaTeX} document +% into which the question content will be inserted. This environment is only used +% for the case of a \app{xelatex} user without \app{Acrobat}. +% The environment writes the is contents verbatim to the file +% \marginpar{\small\raggedleft\texttt{icons-template}}\texttt{icons-template.tex}. +% This file is later input by \cs{@MultiQuesFiles} to build individual +% icon files. +% \begin{macrocode} +\newenvironment{icondoc} +{% + \immediate\openout \wrticonbody icons-template.tex + \let\verbatim@out\wrticonbody + \IWB{\string\RequirePackage{tmp}}% + \verbatimwrite +}{% + \endverbatimwrite + \immediate\closeout \wrticonbody +} +% \end{macrocode} +% \end{environment} +% The prototype, as well as the default definition of \env{icondoc}, based on +% \texttt{examples/\allowbreak advanced/\allowbreak stat\_match1.tex} +% \begin{macrocode} +\ifxetex\ifdpsuseacrobat\else +\begin{icondoc} +\documentclass{article} +\usepackage{web} +\margins{3pt}{3pt}{3pt}{3pt} +\screensize{9\baselineskip}{2.25in} +\parindent0pt +\begin{document} +\small +\dpsInputContent % required, defined in \@MultiQuesFiles +\end{document} +\end{icondoc} +\fi\fi +% \end{macrocode} +% During the course of compiling the icon document, we keep track +% of which questions have an icon. It may be that some questions +% are short enough to fit in the questions area. \cs{addToPageList} +% appearing in both \cs{@SnglQuesFile} and \cs{@MultiQuesFiles}. +% The resulting list \cs{pageList} is automatically written to the +% file \texttt{icons-pglst.sav} at the end of the icon document. +% \begin{macrocode} +\let\pageList\@empty +\def\addToPageList#1{\edef\x{{#1}}\expandafter + \g@addto@macro\expandafter + \pageList\expandafter{\x}} +% \end{macrocode} +% \leavevmode\DescribeMacro\@SnglQuesFile (An internal command) +% Under certain conditions, the command publicly known as \cs{createRequiredIcons}. +% This command is used for non-\app{xelatex} users, and by \app{xelatex} users who +% use \app{Acrobat}. +% \begin{macrocode} +\def\@SnglQuesFile#1#2{% + \@tempcnta#1\relax\advance\@tempcnta\@ne + \edef\N{\the\@tempcnta}% + \@tempcnta\@ne\relax + \@whilenum\@tempcnta < \N \do{% + \begingroup +% \end{macrocode} +% Here is a key point. If the target file does not exist, +% that means that question does not use an icon appearance, +% so we create a blank PDF icon and do not register it +% with \cs{addToPageList}; otherwise, we do register it +% with \cs{addToPageList}. +% \begin{macrocode} + \InputIfFileExists{#2-sc(\the\@tempcnta).cut} + {\addToPageList{\the\@tempcnta}}{\null}\par + \endgroup +% \end{macrocode} +% One icon per page. +% \begin{macrocode} + \newpage + \advance\@tempcnta\@ne + }% +} +% \end{macrocode} +% \leavevmode\DescribeMacro\@MultiQuesFiles +% This command is publicly known as \cs{createRequiredIcons} +% when the author is a \app{xelatex} user who does not have \app{Acrobat}. +% \par\medskip\noindent +% \textbf{Problem with xelatex.} When it comes to embedding a PDF in the document, +% \app{xelatex} does not recognize the \texttt{page} key; as a result, the questions +% must be wrapped in a separate icon file to be later imported into the puzzle document. +% In all other cases, we can conveniently place a questions in a single icon file, and +% import a particular page into the document corresponding to the question. +% \begin{macrocode} +\def\@MultiQuesFiles#1#2{% + \@tempcnta#1\relax\advance\@tempcnta\@ne + \edef\N{\the\@tempcnta}% + \@tempcnta\@ne\relax + \@whilenum\@tempcnta < \N \do{% + \IfFileExists{#2-sc(\the\@tempcnta).cut} + {\addToPageList{\the\@tempcnta}}{} +% \end{macrocode} +% The above lines are the same as in \cs{@SnglQuesFile}. Here's +% where we differ. We begin by creating a temporary package named +% \pkg{tmp} that contains the definition of \cs{dpsInputContent}. +% \begin{macrocode} + \immediate\openout\wrtPkg tmp.sty + \IWP{\string\def\string\dpsInputContent{\string + \InputIfFileExists{#2-sc(\the\@tempcnta).cut}% + {}{\string\null}}}% + \immediate\closeout\wrtPkg +% \end{macrocode} +% Key to the workflow for the author using \app{xelatex} without \app{Acrobat} +% is to use \marginpar{\small\raggedleft\cs{ShellEscape}}\cs{ShellEscape}. +% We compile (using \app{xelatex}) \texttt{icons-template} twice, for no apparent +% reason, followed by renaming the resultant PDF to \texttt{icons-\ameta{num}.pdf}, +% which is the name expected by the puzzle document. +% \begin{macrocode} + \ShellEscape{xelatex icons-template.tex}% + \ifdpscomptwice\ShellEscape{xelatex icons-template.tex}\fi + \ShellEscape{copy icons-template.pdf icons-\the\@tempcnta.pdf}% + \advance\@tempcnta\@ne + }\null % content for the icons.tex file +% \end{macrocode} +% We finish up by deleting all of working files, including the temporary +% package \pkg{tmp}. +% \begin{macrocode} + \ShellEscape{del tmp.sty icons-template.*}% +} +% \end{macrocode} +% \begin{macro}{\createRequiredIcons}\hskip-\marginparsep +% \texttt{\darg{\ameta{n-ques}}\darg{\ameta{puzzle-basename}}} This command creates +% either a single file containing \ameta{n-ques} pages of the required icons, or it creates \ameta{n-ques} +% icon files, each file containing one of the questions. For non-\app{xelatex} users, we use +% \cs{@SnglQuesFile} if the \opt{useacrobat} option is taken, otherwise, we use +% \cs{@MultiQuesFiles}. In all other cases, \cs{@SnglQuesFile} is used. +% \begin{macrocode} +\ifxetex + \ifdpsuseacrobat + \let\createRequiredIcons\@SnglQuesFile + \else + \let\createRequiredIcons\@MultiQuesFiles + \fi +\else + \let\createRequiredIcons\@SnglQuesFile +\fi +% \end{macrocode} +% This JavaScript is used by \app{xelatex} users who have \app{Acrobat}. +% I should mention, this code assumes the document author has \pkg{aeb\_pro} installed, +% including, most importantly, the correct installation of +% \marginpar{\small\raggedleft\texttt{aeb.js \& aeb\_pro.js}}\texttt{aeb.js} and \texttt{aeb\_pro.js}. +% \end{macro} +% \begin{macrocode} +\begin{defineJS}[\def\defineJSjsR{^^J}]{\execExplode} +/* Extract pages to folder */ +// Regular expression used to acquire the base name of file +try { + for (var i = 0; i < this.numPages; i++) + aebTrustedFunctions(this,aebExtractPages,{ + nStart: i, + cPath: "icons-" + (i+1) +".pdf" + }); +} catch (e) { console.println("Aborted: " + e); } +\end{defineJS} +% \end{macrocode} +% Write the file \texttt{icons-pglst.sav} at end of the document. +% \begin{macrocode} +\def\wrtPageList{\newwrite\pagelist + \immediate\openout \pagelist icons-pglst.sav + \immediate\write\pagelist{\string\def\string\pagelist{\pageList}} + \immediate\closeout\pagelist +} +% \end{macrocode} +% One last case for \app{xelatex} users. If the author has \app{Acrobat}, +% we ``explode'' the single icon document into into its individual pages +% with the correct naming convention. +% \begin{macrocode} +\ifxetex\ifdpsuseacrobat +\begin{execJS}{expl} +\execExplode +\end{execJS} +\fi\fi +% \end{macrocode} +% Finally, we write \texttt{icons-pglst.sav} and the end of the document. +% \begin{macrocode} +\AtEndDocument{\wrtPageList} +\let\WriteBookmarks\relax +% \end{macrocode} +% \begin{macrocode} +% \end{macrocode} +% \begin{macrocode} +%</icondoc> +% \end{macrocode} +% \subsection{OCG methods} +% Using OCG methods does not require an ``\texttt{icons.tex}'' file, the puzzle file +% is entirely self contained. The questions are typeset into their own layer, which we make +% visible or invisible, depending on the question selected. We require the +% \marginpar{\raggedleft\small\pkg{aeb\_pro} required}\pkg{aeb\_pro} +% package (with its \opt{uselayers} option) to be properly installed with its JS files, +% as described in the manual of that package. +% In the preamble you can conveniently type, +%\begin{verbatim} +% \usepackage[% +% web={pro,tight}, +% eforms, +% uselayers +% ]{aeb_pro} +%\end{verbatim} +% \begin{macrocode} +%<*ocgadv> +% \end{macrocode} +% Define hooks into the question checkbox event. +% The two commands \cs{afterQhookA} and \cs{OnFocusQhookAA} are hooks onto +% the \cs{dpsQ} command. This allows us to post process +% the user's choice of a questions, and allows us to execute JS on focus. +% \begin{macrocode} +\@ifpackageloaded{textpos}{\let\dps@mode\par}{\let\dps@mode\relax} +\def\afterQhookA#1{% + if(!event.target.isBoxChecked(0))dpsHideLayer("#1");\r + else\pdfSP if(PlayerSignIn())dpsShowLayer("#1");} +\def\OnFocusQhookAA#1{dpsHidePreviousLayer("#1")} +% \end{macrocode} +% Parse the argument (\ameta{name}-\ameta{num}) to get the \ameta{name}. +% \begin{macrocode} +\def\dps@getOCGName#1-#2\@nil{\def\dps@OcgName{#1}} +% \end{macrocode} +% \leavevmode\DescribeMacro\fmtOCGQues\hskip-\marginparsep\texttt{\darg{\ameta{various}}} +% Use this command to format the question layer. Within the argument of \ameta{various} you +% should place \verb~\dpsQuesLayer{#1}~, which input the content file \cs{jobname-sc(\#1).cut}. +% The following two examples use \pkg{eso-pic} and \pkg{textpos} packages respectively. +%\begin{verbatim} +%\fmtOCGQues{% eso-pic pkg +% \parbox[t][9\baselineskip][t]{2.25in}{\kern0pt\small\hfuzz11pt +% \psshadowbox[framesep=0pt]{\fcolorbox{red}{cornsilk}{% +% \parbox{\linewidth}{\dpsQuesLayer{#1}\vskip3pt}}}}} +% +%\fmtOCGQues{% textpos pkg +% \parbox[t][9\baselineskip][t]{2.25in}{\kern0pt\small\hfuzz11pt +% \psshadowbox[framesep=0pt]{\fcolorbox{red}{cornsilk}{% +% \parbox{\linewidth}{\dpsQuesLayer{#1}\vskip3pt}}}}} +%\end{verbatim} +% \begin{macrocode} +\def\fmtOCGQues#1{\def\fmtOCGQues@i##1{#1}} +% \end{macrocode} +% \leavevmode\DescribeMacro\dpsQuesLayer\hskip-\marginparsep\texttt{\darg{\ameta{\ameta{name}-\ameta{num}}}} +% Inputs the appropriate content file. The command is placed in the \cs{fmtOCgQues} and its argument remains +% symbolic (\verb~\dpsQuesLayer{#1}~), as seen in the examples above. The argument is never specified explicitly, +% but is only symbolically referenced with the \cs{placeQuesLayer} command; for example, +%\begin{verbatim} +% \placeQuesLayer{% eso-pic pkg +% \AddToShipoutPictureFG*{\AtTextCenter{\put(-72,72) +% {\insertQuesLayer{#1}}}}} +% +% \placeQuesLayer{% textpos pkg +% \begin{textblock*}{2.25in}[0,0](2.5in+.725in,3in) +% \insertQuesLayer{#1} +% \end{textblock*}} +%\end{verbatim} +% \begin{macrocode} +\def\dpsQuesLayer#1{\input{\jobname-sc(#1).cut}} +% \end{macrocode} +% \leavevmode\DescribeMacro\placeQuesLayer\texttt{\darg{\ameta{various}}} Use this command +% to place your question content on the page. The argument \ameta{various} depends on the +% package used (\pkg{eso-pic} or \pkg{textpos}. Examples are shown above under \cs{dpsQuesLayer}. +% \begin{macrocode} +\long\def\placeQuesLayer#1{\@ifundefined{textblock} + {\let\dps@mode\relax}{\let\dps@mode\par}% + \def\pl@ceQuesL@yer##1{\dps@mode #1}} +% \end{macrocode} +% \leavevmode\DescribeMacro\placeOtherLayer\texttt{\darg{\ameta{various}}} A general purpose +% command for creating another layer, not associated with a question. The \ameta{various} +% argument is roll-your-own for inserting a graphic in a layer with a specific name. For example, +%\begin{verbatim} +% \placeOtherLayer{% eso-pic pkg +% \AddToShipoutPictureFG*{\AtTextCenter{\put(-72,36) +% {\xBld{owclogo}\parbox{2.25in} +% {\includegraphics[width=\linewidth]{owc_self}}\eBld}}}} +%\end{verbatim} +%The above creates a layer named \texttt{owclogo} consisting of a graphic. The placement +%is indicated as well. +% \begin{macrocode} +\long\def\placeOtherLayer#1{#1} +% \end{macrocode} +% \DescribeMacro\insertQuesLayer\hskip-\marginparsep\texttt{\darg{\ameta{name}-\ameta{num}}} +% Places the formatted question content (\cs{fmtOCGQues@i}) within a layer +% created by the \cs{xBld}/\allowbreak\cs{eBld} pair, the layer's name is \ameta{name} (parsed +% as \cs{dps@OcgName}). +% \begin{macrocode} +\def\insertQuesLayer#1{\dps@getOCGName#1\@nil + \edef\x{\noexpand\xBld{\dps@OcgName}}\x + \fmtOCGQues@i{#1}\eBld} +% \end{macrocode} +% \DescribeMacro\quesNumTxt\cs{quesNumTxt} and \DescribeMacro\quesNumTxTPost +% \cs{quesNumTxTPost} are the same, as described for button icon appearances. +% \begin{macrocode} +\newcommand{\quesNumTxt}[1]{\protect\textbf{Problem #1}} +\newcommand{\quesNumTxTPost}{\protect\newline} +% \end{macrocode} +% \leavevmode\DescribeEnv{setContent}\hskip-\marginparsep\texttt{\darg{\ameta{name}}} +% The \env{setContent} is the counterpart +% to the environment of the same name for button icon appearances. +% It performs a similar function, but yet is different. The \env{setContent} +% environment is placed within the \env{cQ} environment. The \env{setContent} follows +% the question prompt. +% \begin{macrocode} +\newenvironment{setContent}[1]{% + \gdef\scArg{#1}% save the argument for the end env +% \end{macrocode} +% The \cs{jobname-sc} CUT file is indexed by \ameta{name}-\cs{theenumi}. +% Thus, we have the \ameta{name} and problem number available to us. +% \begin{macrocode} + \def\CommentCutFile{\jobname-sc(#1-\theenumi).cut}% + \immediate\openout\CommentStream=\CommentCutFile + \begingroup + \set@display@protect + \let\verbatim@out\CommentStream + \dps@IWVO{\quesNumTxt{\theenumi}\quesNumTxTPost}% + \set@typeset@protect + \verbatimwrite +}{% + \endverbatimwrite + \endgroup + \immediate\closeout\CommentStream + \edef\x{\noexpand\pl@ceQuesL@yer{\scArg-\theenumi}}\x +} +% \end{macrocode} +% \subsubsection{Support for a sideshow} +% \leavevmode\DescribeMacro\insertSideshow\hskip-\marginparsep +% \texttt{[\ameta{ext}]\darg{\ameta{rows}}\darg{\ameta{cols}}[\ameta{hy-opts}]\darg{\ameta{path}}} +% Command for placing the tiles of the picture. We assume that the pictures are numbered +% consecutively across rows. +%\begin{quote} +%\begin{description} +% \item[\ameta{ext}] optional extension of the image +% \item[\ameta{rows}] number of rows +% \item[\ameta{cols}] number of columns +% \item[\ameta{hy-opts}] optional arguments for the \cs{includegraphics} command +% \item[\ameta{path}] base name of picture files (The files are index as follows: +% \texttt{mypic\_01}, \texttt{mypic\_02}, \texttt{mypic\_03}, \dots. The basename is +% \texttt{mypic}, the underscore is added in by this command. +%\end{description} +%\end{quote} +% Usage: \begin{flushleft}\quad\verb~\insertSideshow{3}{2}[width=.5\linewidth]{flowers2/rose}~\end{flushleft} +% \begin{macrocode} +\newcommand{\insertSideshow}[3][]{\begingroup + \def\@Ext{#1}\ifx\@Ext\@empty\else\def\@Ext{.#1}\fi + \def\@nrows{#2}\def\@ncols{#3}\insertSideshow@i +} +\newcommand\insertSideshow@i[2][]{\offinterlineskip + \@tempcnta\z@ + \let\DPSIndxList\@gobble + \multido{\iR=1+1}{\@nrows}{\hbox{% + \multido{\iC=1+1}{\@ncols}{% + \global\advance\@tempcnta\@ne + \ifnum\@tempcnta<10\relax + \edef\x{0\the\@tempcnta}\else\edef\x{\the\@tempcnta}\fi + \edef\z{\noexpand\g@addto@macro\noexpand\DPSIndxList{,"\x"}}\z + \xBld{pic\x}\includegraphics[#1]{#2_\x\@Ext}\eBld + }% inner multido + }}% hbox, outer multido +% \end{macrocode} +% Write the results of building the \cs{DPSIndxList} to the aux file. A typical +% result is \verb~\gdef\DPSIndxList{"01","02","03","04","05","06"}~, which are the +% indices for the sideshow picture graphics. +% \begin{macrocode} + \immediate\write\@auxout{\string\gdef\string + \DPSIndxList{\DPSIndxList}}% + \endgroup +} +% \end{macrocode} +% \begin{macrocode} +%</ocgadv> +% \end{macrocode} +% \section{Language Cutomizations} +% Below are the strings that are displayed in the message box. Wording may be +% changed to suite your needs.\par\medskip\noindent +% (2020/04/21) Changed \texttt{( nMissed > n )} to \texttt{( nMissed > nPassing )} +% in the definition of \cs{congratFinished}. +% \changes{v1.1}{2020/04/21}{In the definition of \string\cs{regretPleased}, +% changed \string\texttt{( nMissed > n )} to \string\texttt{( nMissed > nPassing )}} +% \begin{macrocode} +%<*english> +\def\chooseQ{"You must choose a question to answer before you answer!"} +\def\triedTooMuch{"You have tried this problem too many times, + I'm adding " + + \dspenaltypoints + + " points, and resetting the penalty counter. Bad boy/girl!"} +\def\congratFinished{"Congratulations! You finished the puzzle" + +((nMissed==0) ? " without missing a single problem, amazing!" + : ", but you missed " + nMissed + " questions in the process!")} +\def\regretPleased{(( nMissed > nPassing ) + ? "I regret to report that you did not pass the test because + you missed too many questions." + : "I am pleased to report that you passed the test!")} +\def\reportPenaltyPoints{"The number of penalty points is " + + nPenaltyPoints +"."} +\def\finalPenaltyScore{"Final penalty score is " + + nTotalPenaltyPoints + ". "} +\def\aPenaltyScale{[-1,0], [0,4], [4, 10], [10,25], [25,5000]} +\def\aPenaltyMsgs +{% + "Perfect!", + "Very nice performance!", + "This is not looking good. Perhaps a review is in order!", + "Are you trying? No one could do so badly, you only need a + seventh grade education!", + "You're hopeless!" +} +\dlJSStr[noquotes]{\signInMsg}{% + You must enter your name in the field at the top of + the page to get credit for this assignment.} +%</english> +%<*german> +\def\chooseQ{"Du musst erst eine Frage ausw\string\344hlen bevor + Du antwortest!"} +\def\triedTooMuch{"Du hast es leider zu oft versucht, ich + z\string\344hle " + \dspenaltypoints + + " Punkte dazu und setze den Z\string\344hler dann zur\string\374ck. + Bitte streng Dich an!"} +\def\congratFinished{"Herzlichen Gl\string\374ckwunsch! Du hast das + Puzzle beendet" + ((nMissed==0) ? + " ohne auch nur einen Fehler zu machen, wunderbar!" : + ", aber leider " + nMissed + " Mal falsch geantwortet!")} +\def\regretPleased{(( nMissed > nPassing ) + ? "Ich bedauere Dir mitteilen zu m\string\374ssen, dass Du den Test + leider nicht bestanden hast, weil Du zu viele Fragen falsch + beantwortet hast." + : "Ich bin \string\344usserst erfreut Dir mitteilen + zu d\string\374rfen, dass Du den Test bestanden hast!")} +\def\reportPenaltyPoints{"Die Anzahl der Strafpunkte ist " + + nPenaltyPoints +"."} +\def\finalPenaltyScore{"Die Gesamtanzahl der Strafpunkte ist damit " + + nTotalPenaltyPoints + ". "} +\def\aPenaltyScale{[-1,0], [0,4], [4, 10], [10,25], [25,5000]} +\def\aPenaltyMsgs +{% + "Perfekt!", + "Sehr gute Vorstellung!", + "Es sieht nicht sonderlich gut aus. Vielleicht w\string\344re + eine Wiederholung gut!", + "R\string\344tst Du eigentlich nur? Niemand kann wirklich so + schlecht sein. Das ist Stoff aus der siebten Klasse!", + "Du bist ein hoffnungsloser Fall!" +} +\dlJSStr[noquotes]{\signInMsg}{% + You must enter your name in the field at the top of + the page to get credit for this assignment.} +%</german> +%<*package> +% \end{macrocode} +% +% \section{Form and document actions} +% +% \begin{macro}{\printPDF}\hskip-\marginparsep\texttt{[\ameta{opts}]\darg{\ameta{wd}}\darg{ht}} +% Opens the print dialog box, pre-populates some print parameters. +% \begin{macrocode} +\newcommand{\printDPS}[3][]{% + \pushButton[\CA{Print}\A{\JS{% + var pp = this.getPrintParams();\r + pp.firstPage=1;\r + pp.lastPage=1;\r + pp.pageHandling = pp.constants.handling.shrink;\r + var fv = pp.constants.flagValues;\r + pp.flags |= (fv.suppressCenter | fv.suppressRotate);\r + this.print(pp);}}#1]{printDPS}{#2}{#3}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\resetPDF}\hskip-\marginparsep\texttt{[\ameta{opts}]\darg{\ameta{wd}}\darg{ht}} +% Clears the puzzle board. +% \begin{macrocode} +\newcommand{\resetDPS}[3][]{% + \pushButton[\CA{Clear}\A{\JS{resetDPS();}}#1]{resetDPS}{#2}{#3}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\clearOnCloseOrSave} +% Try to prevent the student from saving the game (for some other student) +% we clear the game board if either student closes or save the document. +% \begin{macrocode} +\def\dpsWCSWrnMsg{The file dps-wcs.def could not be found} +\newcommand{\clearOnCloseOrSave}{\InputIfFileExists{dps-wcs.def}{} + {\PackageWarning{dps}{\dpsWCSWrnMsg}}} +% \end{macrocode} +% \end{macro} +% \begin{macrocode} +%</package> +%<*willCloseSave> +% \end{macrocode} +% This is the mechanism for preventing the student from saving the document +% and continuing at a later time. When the student tries to save or close the document, +% the entire puzzle board is cleared. +% \begin{macrocode} +\begin{willClose} +resetDPS(); +\end{willClose} +\begin{willSave} +resetDPS(); +\end{willSave} +%</willCloseSave> +% \end{macrocode} +% +% \section{JavaScript Support} +% \subsection{JavaScript common to all options} +% \begin{macrocode} +%<*package> +\def\lngthOfMsg{2000} % in milliseconds +% \end{macrocode} +% \leavevmode\DescribeMacro\dpsResetHook\hskip-\marginparsep\texttt{\darg{\ameta{js-code}}} +% Can be used to add code lines to the \texttt{dpsReset()} function. +% \begin{macrocode} +\def\dpsResetHook#1{\def\dpsresethook{#1}} +\dpsResetHook{;} +% \end{macrocode} +% \leavevmode\DescribeMacro\dpsFinishedEvent\hskip-\marginparsep\texttt{\darg{\ameta{js-code}}} +% Can be used to add code lines to the \texttt{dpsFinishedHook()} function, a function that is +% called when the puzzle is complete. +% \begin{macrocode} +\def\dpsFinishedEvent#1{\def\dpsfinishedevent{#1}} +\dpsFinishedEvent{;} +% \end{macrocode} +% The main JavaScript segment for DPS +% \begin{macrocode} +\begin{insDLJS}{match}{DPS: JavaScript support Das Puzzle Spiel} +var playerSignedIn = false; +var missesByQuestion = new Object(); +var nPassing = \dspassing; +var nMissed = 0; +var nPenaltyPoints = 0; +var activeQuestion = ""; +var f=this.getField("ckbxQ"); +var g=f.getArray(); +var QBC=g[0].strokeColor; +var pic = new Object(); +var _dpsTO; // time out variable +var bRandPicMaps=\bRandPicMaps; +% \end{macrocode} +% \leavevmode\IndexJS{PlayerSignIn}\hskip-\marginparsep\texttt{()} Manages whether a player +% must sign into the \texttt{dpsSignInName} field. If this field does not exit, no +% sign-in is required. +% \begin{macrocode} +function PlayerSignIn() +{ + if ( !playerSignedIn ) { + var f = this.getField("dpsSignInName"); + if (f != null) { + var nameField = f.value; + if ( nameField.replace(/\s*/g,"") == "" ) { + app.alert("\signInMsg"); + event.target.value="Off"; + } else + playerSignedIn = true; + } else playerSignedIn = true; + } + return playerSignedIn; +} +% \end{macrocode} +% \leavevmode\IndexJS{processChoice}\hskip-\marginparsep\texttt{(\ameta{name})} This +% is the mouse up action of the answer check boxes. +% \begin{macrocode} +function processChoice(name) +{ + // Get the question field that corresponds to this question, + // see if checked. + var f = this.getField("ckbxQ."+name); + if ( (f != null) && (f.isBoxChecked(0)) ) { // right + clearRedCrosses (); + this.resetForm(["puzzle."+name]); + event.target.textColor = ["RGB", 0, 0.6, 0]; + f.strokeColor = ["RGB", 0, 0.6, 0]; + f.readonly = true; + event.target.readonly=true; + try { afterCorrectChoiceHook() } catch(e) {}; + checkForFinished(); + } else { // wrong + if ( activeQuestion != "" ) + var h = this.getField(activeQuestion); + if ( (activeQuestion=="") || (h.readonly) ) { + // active question already answered + event.target.value = "Off"; + var g = this.getField("report"); + str = \chooseQ; + g.value = str; + var to = app.setTimeOut("clearMessages()", \lngthOfMsg); + } else { + event.target.style = style.cr; + event.target.textColor = color.red; + ++nMissed; + if ( typeof missesByQuestion[activeQuestion] !="number" ) + missesByQuestion[activeQuestion] = 1; + else + missesByQuestion[activeQuestion] += 1; + if (missesByQuestion[activeQuestion] > \dsthreshold) { + var f = this.getField("report"); + str = \triedTooMuch; + f.value = str; + nPenaltyPoints += \dspenaltypoints; + missesByQuestion[activeQuestion] = 0; + clearRedCrosses (); + var to = app.setTimeOut("clearMessages()", \lngthOfMsg); + } + } + } +} +% \end{macrocode} +% \leavevmode\IndexJS{clearMessages}\hskip-\marginparsep\texttt{()} Clears the text +% field named \texttt{report}, which is created by \DescribeMacro\placeMessageField +% \cs{placeMessageField}. +% \begin{macrocode} +function clearMessages() +{ + var f = this.getField("report"); + f.value = ""; +} +% \end{macrocode} +% \leavevmode\IndexJS{clearRedCrosses}\hskip-\marginparsep\texttt{()} Clears +% all answer check boxes what are marked with a cross, meaning wrong choice. +% Part of the mouse up action question check boxes. +% \begin{macrocode} +function clearRedCrosses () +{ + var g = this.getField("ckbxA"); + h = g.getArray(); + for ( i=0; i < h.length; i++) { + if ( h[i].style == style.cr) h[i].checkThisBox(0,false); + h[i].style = style.ch; + } + } +% \end{macrocode} +% \leavevmode\IndexJS{checkForFinished}\hskip-\marginparsep\texttt{()} Determines +% if all questions have been answered. Called from \texttt{processChoice()}. +% \begin{macrocode} +function checkForFinished() +{ + var f = this.getField("puzzle"); + var g = f.getArray(); + var anyEmpty = false; + for ( var i=0; i < g.length; i++) { + if ( (g[i].name != "puzzle.space") && % +(g[i].value.replace(/\s/g,"") == "") ) { + anyEmpty = true; + break; + } + } + var nTotalPenaltyPoints=nMissed + nPenaltyPoints; + if ( !anyEmpty ) { + try { dpsFinishedHook() } catch (e) {}; + var f = this.getField("report"); + str = \congratFinished + + "\n" + \regretPleased + + "\n" + \reportPenaltyPoints + + "\n" + \finalPenaltyScore + + " " + finalRating(nTotalPenaltyPoints); + f.value = str; + } +} +% \end{macrocode} +% \leavevmode\IndexJS{finalRating}\hskip-\marginparsep\texttt{(\ameta{penalty-points})} +% A function that returns a message string from the array (\cs{aPenaltyMsgs}) of penalty messages. +% Choice of messages is based on where the value \ameta{penalty-points} falls into +% the penalty scale array (\cs{aPenaltyScale}). This function is called from +% \texttt{checkForFinished()}. +% \begin{macrocode} +function finalRating(n) { + var aPenaltyScale = new Array( \aPenaltyScale\space); + var aPenaltyMsgs = new Array( \aPenaltyMsgs\space); + for ( var i=0; i<aPenaltyScale.length; i++) + if ( (n > aPenaltyScale[i][0]) && (n <= aPenaltyScale[i][1]) ) + return aPenaltyMsgs[i]; +} +% \end{macrocode} +%\leavevmode\IndexJS{resetDPS}\hskip-\marginparsep\texttt{()} +% A JavaScript function to reset the puzzle board. May be used as a push button +% action or within the \env{willClose} and \env{willSave} environments. +% \changes{v1.1}{2020/04/21}{Added \texttt{resetDPS()} JavaScript function.} +% \begin{macrocode} +function resetDPS() { + this.delay=true; + this.resetForm(); + var f=this.getField("puzzle"); + var g=f.getArray(); + for (var i=0; i<g.length; i++)g[i].value=""; + var f=this.getField("ckbxQ"); + f.strokeColor=QBC; + var g=f.getArray() + for (var i=0; i<g.length; i++)g[i].readonly=false; + var f=this.getField("ckbxA"); + var g=f.getArray(); + for (var i=0; i<g.length; i++)g[i].readonly=false; + this.dirty=false; + if(typeof(xBlds)!="undefined"){ + for (var i=0; i<xBlds.length; i++) { + var bName=xBlds[i].name.substring(3); + toggleSetThisLayer(bName,false); + } + } +% \end{macrocode} +% Hide any form fields with base name of \texttt{btnpic}. +% \begin{macrocode} + var f=this.getField("btnpic"); + if(f!=null)f.display=display.hidden; + try { +% \end{macrocode} +% The hook (\DescribeMacro\dpsresethook\cs{dpsresethook}) to add code lines +% during the reset. +% \begin{macrocode} + \dpsresethook + if (typeof mixupDPS == "function") { + mixupDPS(); + showDPS(); + } + } catch(e){}; + playerSignedIn = false; + missesByQuestion = new Object(); + nMissed = 0; + nPenaltyPoints = 0; + activeQuestion = ""; + aPicIndex=randomizePicList(aPicIndex,bRandPicMaps); + if(bRandPicMaps)assignNamesToIndexes(); + this.delay=false; +} +% \end{macrocode} +% \subsubsection{JavaScript to support a sideshow} +% \begin{macrocode} +/* + Create mapping from letters to pictures +*/ +var aPicIndex=[\DPSIndxList]; +var aNamesList=[\DPSNamesList]; +var diff; +var PIlength=aPicIndex.length; +var NLlength=aNamesList.length; +if ( (diff=NLlength-PIlength) > 0 ) + for (var i=0; i<diff; i++) + aPicIndex.push(null); +// now randomize aPicIndex, if requested +aPicIndex=randomizePicList(aPicIndex,bRandPicMaps); +// now make assignments +assignNamesToIndexes(); +function assignNamesToIndexes() { + for(var i=0; i< NLlength; i++) + pic[aNamesList[i]]=aPicIndex[i]; +} +function randomizePicList(array, bRandomize) { + if (bRandomize) shuffle(array); + return array; +} +% \end{macrocode} +% The shuffle function was obtained from \textsf{stackoverflow}.\footnote +% {\url{stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array}} +% \begin{macrocode} +function shuffle(array) { + var currentIndex = array.length, temporaryValue, randomIndex; + // While there remain elements to shuffle... + while (0 !== currentIndex) { + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + // And swap it with the current element. + temporaryValue = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = temporaryValue; + } + return array; +} +\end{insDLJS} +% \end{macrocode} +% \subsection{JavaScript for the \texorpdfstring{\protect\opt{usebtnappr}}{usebtnappr} option}\label{s:btns} +% \begin{macrocode} +\ifusebtnappr +\begin{insDLJS}{dpsbtnappr}{DPS: Icon appearance support} +% \end{macrocode} +%\leavevmode\IndexJS{dpsShowQues}\hskip-\marginparsep\texttt{(\ameta{num})} +% Part of the mouse-up action of the question check boxes. The function displays +% the hidden appearance icon for this question. +% \begin{macrocode} +function dpsShowQues(n) +{ + if (PlayerSignIn()) { + dpsShowFld("btnQ."+n); +% var f=this.getField("btnQ."+n); +% if (f!=null) f.display=display.visible; + } +} +% \end{macrocode} +%\leavevmode\IndexJS{dpsHideQFields}\hskip-\marginparsep\texttt{()} +% Hides all icons fields with parent name of \texttt{btnQ}. +% \begin{macrocode} +function dpsHideQFields() { + dpsHideFld("btnQ"); +% var f=this.getField("btnQ"); +% f.display=display.hidden; +} +% \end{macrocode} +%\leavevmode\IndexJS{dpsHideFinalField}\hskip-\marginparsep\texttt{(\ameta{name})} +% Hides the additional field that is displayed after player finishes. Typically +% this function is fired by the document author during the \texttt{dpsReset()} function. +% Modification to this function are through the \DescribeMacro\dpsResetHook\cs{dpsResetHook} helper macro. +% For example, +%\begin{verbatim} +% \dpsResetHook{% +% dpsHideQFields(); +% dpsHideFinalField("btnEmoji"); +% } +%\end{verbatim} +% Here, we hide all fields and hide the \texttt{"btnEmoji"} graphic. +% \begin{macrocode} +function dpsHideFinalField(name){ + dpsHideFld(name); +% var f=this.getField(name); +% if (f!=null)f.display=display.hidden; +} +% \end{macrocode} +%\leavevmode\IndexJS{dpsHidePreviousQues}\hskip-\marginparsep\texttt{()} +%This function actually hides all fields, but only if there is an active +%question. +% \begin{macrocode} +function dpsHidePreviousQues() +{ + if ( activeQuestion != "" ) { + dpsHideQFields(); + } +} +function dpsShowFld(name) { + var f=this.getField(name); + if (f!=null)f.display=display.visible; +} +function dpsHideFld(name) { + var f=this.getField(name); + if (f!=null)f.display=display.hidden; +} +% \end{macrocode} +% \begin{macrocode} +function displayPic(name){ +%// var name = activeQuestion.replace(/ckbxQ\./,""); +%// var name = displayPic.name; +% console.println("name: "+name); +% console.println("pic[name]: "+pic[name]); + if (pic[name] != null )dpsShowFld("btnpic."+pic[name]); +} +% \end{macrocode} +%\leavevmode\IndexJS{afterCorrectChoiceHook}\hskip-\marginparsep\texttt{()} +%After a correct answer, we hide all icon fields to get ready for the next question +%or final icon. +% \begin{macrocode} +function afterCorrectChoiceHook() +{ + var name = activeQuestion.replace(/ckbxQ\./,""); + dpsHideQFields(); + displayPic.name=name; + _dpsTO=app.setTimeOut("displayPic('"+name+"')",25); +} +% \end{macrocode} +%\leavevmode\IndexJS{dpsFinishedHook}\hskip-\marginparsep\texttt{()} This function +%fires when all questions have been answered. Called from \texttt{checkForFinished()}. +%This function executes a document authored function, \DescribeMacro\dpsfinishedevent\texttt{dpsfinishedevent}, +%if there is one defined. +% \begin{macrocode} +function dpsFinishedHook() +{ + dpsHideQFields(); + try { + \dpsfinishedevent + if(typeof sortoutDPS == "function") { + ok2Continue = true; + sortoutDPS(); + } + }catch(e){} +} +\end{insDLJS} +% \end{macrocode} +% Bubble sort the pics if \cs{sortPicMappings} is expanded in the preamble. +% \begin{macrocode} +%</package> +%<*sortjs> +\begin{insDLJS}{dpssort}{DPS: Bubble Sort} +// Global Data: +var hasBeenRandomized=false; +var btnbase="btnpic."; // btnpic.01, btnpic.02, etc +var iconbase="pic"; // pic01, pic02, etc. +var nTotalTiles=\dpsNumSideShowPics; +var randomDPS = new Array(nTotalTiles+1); +var ldps = randomDPS.length; +var timeout = 10; +var shutdown; +var debug = false; // memDebug; +var ok2Continue = true; +for (i=1; i<=nTotalTiles; i++) randomDPS[i]=i; +// Mixup DPS: +function mixupDPS() +{ + var i, rand, temp; + for (i=1; i<= nTotalTiles; i++) + { + var rand = Math.random(); + rand *= ldps*ldps; + rand = Math.ceil(rand); + rand = rand \% ldps; + if (rand == 0 ) rand = 1; + temp = randomDPS[i]; + randomDPS[i]=randomDPS[rand]; + randomDPS[rand]=temp; + } +} + +// Show DPS: +function showDPS() +{ +% \sortCustomStartJS + var I,J; + for ( var i=1; i<=nTotalTiles; i++ ) + { + I=((i<10)?"0":"")+i; + J=((randomDPS[i]<10)?"0":"")+randomDPS[i]; + var oIcon = this.getIcon(iconbase+J); +% var oIcon = oIconStreams[iconbase+J]; +% var oIcon = this.getIcon("pic."+randomDPS[i]); + var f = this.getField(btnbase+I); + f.buttonSetIcon(oIcon); + } +} +// Sortout DPS: +function sortoutDPS() +{ + outerLoop(randomDPS.length-1); +} +function outerLoop(i) +{ + if ( ok2Continue && (i >= 0) ) % +shutdown = app.setTimeOut("app.clearTimeOut(shutdown); % +innerLoop("+i+",1);", timeout); + else { +% \sortCustomFinishJS + } +} +function innerLoop(i,j) +{ + var I, J; + if ( j <= i ) + { + if (randomDPS[j-1] > randomDPS[j]) + { + var temp = randomDPS[j-1]; + randomDPS[j-1] = randomDPS[j]; + randomDPS[j] = temp; + J=((randomDPS[j-1]<10)?"0":"")+randomDPS[j-1]; + I=((j-1 < 10)?"0":"")+(j-1); + var oIcon = this.getIcon(iconbase+J); + var f = this.getField(btnbase+I); + f.buttonSetIcon(oIcon); + J=((randomDPS[j]<10)?"0":"")+randomDPS[j]; + I=((j < 10)?"0":"")+j; + var oIcon = this.getIcon(iconbase+J); + var f = this.getField(btnbase+I); + f.buttonSetIcon(oIcon); + } + j++ + if ( ok2Continue ) % +shutdown = app.setTimeOut("app.clearTimeOut(shutdown); % +innerLoop("+i+","+j+");", timeout); + else { +% \sortCustomFinishJS + } + } + else + { + i--; + outerLoop(i); + } +} +\end{insDLJS} +%</sortjs> +%<*package> +\fi +% \end{macrocode} +% \subsection{JavaScript for the \texorpdfstring{\protect\opt{uselayers}}{uselayers} option}\label{s:ocgs} +% We define similar functionality as described in Section~\ref{s:btns}. +% \begin{macrocode} +\ifuseocgappr +\begin{insDLJS}{dpslayer}{DPS: Layer Support} +% \end{macrocode} +%\leavevmode\IndexJS{dpsShowLayer}\hskip-\marginparsep\texttt{(\ameta{name})} +%Show the layer with a name of \ameta{name}. The JavaScript function \IndexJS{toggleSetThisLayer}\texttt{toggleSetThisLayer()} +%is defined in \pkg{aeb\_pro} with the \opt{uselayers} option. +% \begin{macrocode} +function dpsShowLayer(name) +{ + toggleSetThisLayer(name, true); +} +% \end{macrocode} +%\leavevmode\IndexJS{dpsHidePreviousLayer}\hskip-\marginparsep\texttt{()} +%Hides this previous layer, as recored by \texttt{activeQuestion}. The value +%of \texttt{activeQuestion} is of the form \texttt{ckbxQ.\ameta{name}}. We strip +%off the first 6 letters in this string. +% \begin{macrocode} +function dpsHidePreviousLayer() +{ + if ( activeQuestion != "" ) { +% var activename = activeQuestion.replace(/ckbxQ\./,""); + var activename=activeQuestion.substring(6) + dpsHideLayer(activename); + } +} +% \end{macrocode} +%\leavevmode\IndexJS{dpsHideLayer}\hskip-\marginparsep\texttt{(\ameta{name})} +%Hide the layer with a name of \ameta{name}. The function \IndexJS{toggleSetThisLayer}\texttt{toggleSetThisLayer()} +%is defined in \pkg{aeb\_pro} with the \opt{uselayers} option. +% \begin{macrocode} +function dpsHideLayer(name) +{ + toggleSetThisLayer(name, false); +} +% \end{macrocode} +%\leavevmode\IndexJS{afterCorrectChoiceHook}\hskip-\marginparsep\texttt{()} +%A function that fires after a correct answer is registered. +% \begin{macrocode} +function afterCorrectChoiceHook() +{ + var name = activeQuestion.replace(/ckbxQ\./,""); + try { +% \end{macrocode} +% Used for special effects. +% \begin{macrocode} + if (pic[name] != null ) + dpsShowLayer("pic"+pic[name]); + } catch(e) {}; + dpsHideLayer(name); +} +% \end{macrocode} +%\leavevmode\IndexJS{dpsFinishedHook}\hskip-\marginparsep\texttt{()} This function +%fires when all questions have been answered. Called from \texttt{checkForFinished()}. +%This function executes a document authored function, \DescribeMacro\dpsfinishedevent\texttt{dpsfinishedevent}, +%if there is one defined. +% \begin{macrocode} +function dpsFinishedHook() +{ + var name = activeQuestion.replace(/ckbxQ\./,""); + dpsHideLayer(name); + try { + \dpsfinishedevent + }catch(e){} +} +\end{insDLJS} +\fi +\dps@restoreCats +\let\WriteBookmarks\relax +%</package> +% \end{macrocode} +% \Finale +\endinput diff --git a/texmf-dist/source/latex/dps/dps.ins b/texmf-dist/source/latex/dps/dps.ins index e6d567e8..ecaabf2f 100644 --- a/texmf-dist/source/latex/dps/dps.ins +++ b/texmf-dist/source/latex/dps/dps.ins @@ -1,61 +1,65 @@ -%%
-%% This file will generate fast loadable files and documentation
-%% driver files from the doc files in this package when run through
-%% LaTeX or TeX.
-%%
-%% Copyright 1999-2006 D. P. Story
-%%
-%% This file is part of the `AcroTeX eDucation Bundle'.
-%% -------------------------------------------
-%%
-%% It may be distributed under the conditions of the LaTeX Project Public
-%% License, either version 1.2 of this license or (at your option) any
-%% later version. The latest version of this license is in
-%% http://www.latex-project.org/lppl.txt
-%% and version 1.2 or later is part of all distributions of LaTeX
-%% version 1999/12/01 or later.
-%%
-%% --------------- start of docstrip commands ------------------
-%%
-\def\filedate{2001/05/26}
-\def\batchfile{dps.ins}
-%
-\input docstrip
-\ifx\generate\undefined
- \Msg{**********************************************}
- \Msg{*}
- \Msg{* This installation requires docstrip}
- \Msg{* version 2.4 or later.}
- \Msg{*}
- \Msg{* An older version of docstrip has been input}
- \Msg{*}
- \Msg{**********************************************}
- \errhelp{Move or rename old docstrip.tex and get a newer one.}
- \errmessage{Old docstrip in input path}
- \batchmode
- \csname @@end\endcsname\end
-\fi
-
-\keepsilent
-\askforoverwritefalse
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\preamble
-\endpreamble
-\generate
-{%
- \file{dps.sty}{\from{dps.dtx}{copyright,package}}
- \file{dps_str_us.def}{\from{dps.dtx}{copyright,english}}
- \file{dps_str_de.def}{\from{dps.dtx}{copyright,german}}
-}
-
-\Msg{***************************************************************}
-\Msg{*}
-\Msg{* \space To finish the installation you have to copy the files }
-\Msg{*}
-\Msg{* \space *.sty, *.cfg and *.def into a directory searched by TeX}
-\Msg{*}
-\Msg{***************************************************************}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\endinput
+%% +%% This file will generate fast loadable files and documentation +%% driver files from the doc files in this package when run through +%% LaTeX or TeX. +%% +%% Copyright (C) 2006--2020 D. P. Story +%% +%% ------------------------------------------- +%% +%% It may be distributed under the conditions of the LaTeX Project Public +%% License, either version 1.2 of this license or (at your option) any +%% later version. The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.2 or later is part of all distributions of LaTeX +%% version 1999/12/01 or later. +%% +%% --------------- start of docstrip commands ------------------ +%% +\def\filedate{2006/10/06} +\def\batchfile{dps.ins} +% +\input docstrip +\ifx\generate\undefined + \Msg{**********************************************} + \Msg{*} + \Msg{* This installation requires docstrip} + \Msg{* version 2.4 or later.} + \Msg{*} + \Msg{* An older version of docstrip has been input} + \Msg{*} + \Msg{**********************************************} + \errhelp{Move or rename old docstrip.tex and get a newer one.} + \errmessage{Old docstrip in input path} + \batchmode + \csname @@end\endcsname\end +\fi + +\keepsilent +\askforoverwritefalse +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\preamble +\endpreamble +\generate +{% + \file{dps.sty}{\from{dps.dtx}{copyright,package}} + \file{usebtnappr.def}{\from{dps.dtx}{copyright,btnadv}} + \file{useocgappr.def}{\from{dps.dtx}{copyright,ocgadv}} + \file{sortjs.def}{\from{dps.dtx}{copyright,sortjs}} + \file{icon-doc.sty}{\from{dps.dtx}{copyright,icondoc}} + \file{dps-wcs.def}{\from{dps.dtx}{willCloseSave}} + \file{dps_str_us.def}{\from{dps.dtx}{copyright,english}} + \file{dps_str_de.def}{\from{dps.dtx}{copyright,german}} +} + +\Msg{***************************************************************} +\Msg{*} +\Msg{* \space To finish the installation you have to copy the files } +\Msg{*} +\Msg{* \space *.sty, *.cfg and *.def into a directory searched by TeX} +\Msg{*} +\Msg{***************************************************************} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\endinput |