%\iffalse % probsoln.dtx generated using makedtx version 0.94b (c) Nicola Talbot % Command line args: % -src "(.+)\.(sty)=>\1.\2" % -doc "manual.tex" % -author "Nicola Talbot" % -dir "source" % probsoln % Created on 2007/8/21 16:58 %\fi %\iffalse %<*package> %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z %% Digits \0\1\2\3\4\5\6\7\8\9 %% Exclamation \! Double quote \" Hash (number) \# %% Dollar \$ Percent \% Ampersand \& %% Acute accent \' Left paren \( Right paren \) %% Asterisk \* Plus \+ Comma \, %% Minus \- Point \. Solidus \/ %% Colon \: Semicolon \; Less than \< %% Equals \= Greater than \> Question mark \? %% Commercial at \@ Left bracket \[ Backslash \\ %% Right bracket \] Circumflex \^ Underscore \_ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} % %\fi % \iffalse % Doc-Source file to use with LaTeX2e % Copyright (C) 2007 Nicola Talbot, all rights reserved. % \fi % \iffalse %<*driver> \documentclass{ltxdoc} \usepackage[colorlinks, bookmarks, hyperindex=false, pdfauthor=Nicola Talbot, pdftitle={probsoln.sty : a LaTeX2e package to help create problem sheets}]{hyperref} \newcommand{\sty}[1]{\textsf{#1}}\newcommand{\env}[1]{\textsf{#1}} \newcommand{\cmddef}[1]{\hypertarget{#1}{\cmdname{#1}}} \newcommand{\cmdlink}[1]{\hyperlink{#1}{\cmdname{#1}}} \newcommand{\problabel}[2]{\hypertarget{#1}{\texttt{#2}}} \newcommand{\probref}[1]{\hyperlink{#1}{\texttt{#1}}} \newcommand{\cmdname}[1]{\cs{#1}} %hyperindex conflicts with doc %(end up with |usage|hyperpage in indexentry) \renewcommand{\usage}[1]{\textit{\hyperpage{#1}}} \renewcommand{\main}[1]{\hyperpage{#1}} \newcommand{\see}[2]{\emph{see} #1} \makeatletter \def\index@prologue{\section*{Index}} \makeatother \CheckSum{499} \OnlyDescription \PageIndex \begin{document} \DocInput{probsoln.dtx} \end{document} % %\fi % \title{probsoln.sty v2.04: \LaTeXe\ Package to help create problem sheets} % \author{Nicola L.C. Talbot} % \date{21st August 2007} % \maketitle % \tableofcontents % % \section{Introduction} %The \sty{probsoln} package is designed for teachers or %lecturers who want to create problem sheets for their %students. This package was designed with specifically %mathematics problems in mind, but can be used for other %subjects as well. The idea is to create a file containing a %large number of problems with their solutions which can be %read in by \LaTeX, and then select a number of problems to %typeset. This means that once the database has been set up, %each year you can easily create a new problem sheet that is %sufficiently different from the previous year, thus %preventing the temptation of current students seeking out %the previous year's students, and checking out their %answers. There is also an option that can be passed to the %package to determine whether or not the solutions should be %printed. In this way, one file can either produce the %student's version or the teacher's version. % %\section{Package Options} %The following options may be passed to this package: %\begin{center} %\begin{tabular}{@{\ttfamily}ll} %answers & Show the answers\\ %noanswers & Don't show the answers (default) %\end{tabular} %\end{center} % %\section{Creating a New Problem} %\DescribeMacro{\newproblem} %\cmddef{newproblem}\verb|[|\meta{nargs}\verb/]{/\meta{label}\verb!}{!\meta{problem}\verb+}{+\meta{solution}\verb=}=\\[10pt] %A new problem is defined using the command %\cmdname{newproblem}. This does not print anything, %but merely stores the problem. As from version 2.03, there is also %a starred version of this command for problems without a solution %(for example, essay style questions):\\[10pt] %\DescribeMacro{\newproblem*} %\cmddef{newproblem*}\verb|[|\meta{nargs}\verb/]{/\meta{label}\verb!}{!\meta{problem}\verb+}+\\[10pt] %The argument \meta{label} is %a unique string that is assigned to this problem so that it %can be used later. The argument \meta{problem} is normal %\LaTeX\ code that should be used to typeset the problem. %The argument \meta{solution} is normal \LaTeX\ code that %should be used to typeset the solution, if required. For %example, the following defines a problem with the label %\problabel{quaddiff}{quaddiff}: %\begin{verbatim} % \newproblem{quaddiff}{% % %This is the problem % \begin{displaymath} % f(x) = x^2 + 3x + 4 % \end{displaymath} % }{% % %This is the solution % \begin{displaymath} % f'(x) = 2x + 3 % \end{displaymath} % } %\end{verbatim} %The following is an essay question, so doesn't come with a solution: %\begin{verbatim} %\newproblem*{inheritance}{Describe what is meant by the term %\emph{inheritance} in object-oriented programming. Use examples.} %\end{verbatim} % %The optional argument \meta{nargs} specifies the number of %parameters this problem will take. By default this value is %0, but any value from 1 to 9 may be used. Each parameter is %referred to by \verb|#1|, \verb/#2/, \ldots, \verb!#9!. %For example, the following problem, labelled \problabel{sindiff}{sindiff}, %takes one parameter: %\begin{verbatim} %\newproblem[1]{sindiff}{% %\(f(x) = \sin(#1x)\) %}{% %\(f'(x) = #1\cos(#1x)\) %} %\end{verbatim} % %The \probref{quaddiff} problem shown above can be made more %generic by using parameters\problabel{diff:quad}{}: %\begin{verbatim} %\newcount\ctr %\newproblem[3]{diff:quad}{% %\(f(x) = %\ifnum#1=0 %\else %\ifnum#1=1\else#1\fi x^2 %\fi %\ifnum#2=0 %\else %\ifnum#2>0 \ifnum#1=0 \else + \fi \fi %\ifnum#2=1\else#2\fi x %\fi %\ifnum#3=0 %\else %\ifnum#3>0 \ifnum#2=0 \ifnum#1=0 \else + \fi \else + \fi\fi %#3 %\fi\) %}{% %\(f'(x) = %\ifnum#1=0 %\else %\ctr=2 %\multiply\ctr by #1 %\the\ctr x %\fi %\ifnum#2=0 %\else %\ifnum#2>0 \ifnum#1=0 \else + \fi \fi %#2 %\fi % % print 0 if both #1 and #2 are 0 %\ifnum#1=0 \ifnum#2=0 0 \fi\fi %\) %} %\end{verbatim} %The three parameters correspond to the coefficients. Note %that they must all be integers since \TeX\ only performs %integer arithmetic. % %\section{Creating a Database} % %To generate a database, simply create a \texttt{.tex} file %where all the problems are defined using \cmdlink{newproblem} or %\cmdlink{newproblem*}, %and either \cmdname{input} it at the start of your document if %you want to use specific problems (see Section~\ref{sec:useprob}), or pass it to %\cmdname{selectrandomly} (see Section~\ref{sec:selran}). This package %comes with some sample databases, along with some sample documents %that use these databases. % %\section{Displaying a Problem} %\label{sec:useprob} % \DescribeMacro{\useproblem} %\cmddef{useproblem}\verb|{|\meta{label}\verb/}/\\[10pt] %Once a problem has been defined using \cmdlink{newproblem}, it %can be typeset using the command \cmdname{useproblem}. If the %problem was defined to take arguments, the arguments to the %problem should come after the label. In the case of the %\probref{sindiff} example above, the command %\verb|\useproblem{sindiff}{2}| would produce the following:\\[10pt] % $f(x) = \sin(2x)$ \paragraph{Solution:} $f'(x) = 2\cos(2x)$\\[10pt]whereas the command \verb|\useproblem{diff:quad}{3}{0}{-2}| would produce:\\[10pt] % $f(x) = 3x^2 - 2$ \paragraph{Solution:} $f'(x) = 6x$\vspace{10pt} % %Suppose all the above problems are defined in the file %\texttt{probs.tex}, then the following code will create a %problem sheet with four questions in it: %\begin{verbatim} %\documentclass{article} % %\usepackage{probsoln} %\input{probs} % %\begin{document} %Differentiate the following functions with respect to $x$: %\begin{enumerate} %\item \useproblem{quaddiff} %\item \useproblem{sindiff}{4} %\item \useproblem{diff:quad}{2}{3}{1} %\item \useproblem{diff:quad}{0}{1}{2} %\end{enumerate} %\end{document} %\end{verbatim} %The answer sheet can then be generated by passing the option %\texttt{answers} to the \texttt{probsoln} package. % %\section{Selecting All Problems} % %To select all problems defined in a database, in the order in %which they were defined, use the command: %\DescribeMacro{\selectallproblems} %\cmddef{selectallproblems}\verb|{|\meta{filename}\verb/}/ %For example, suppose the problems are defined in the file %\texttt{easy.tex}, then the following will create a problem sheet %which uses all these problems: %\begin{verbatim} %\documentclass[a4paper]{article} % %\usepackage{probsoln} % %\begin{document} %Differentiate the following functions: %\begin{enumerate} %\selectallproblems{easy} %\end{enumerate} %\end{document} %\end{verbatim} % %\section{Selecting Problems at Random} %\label{sec:selran} % \DescribeMacro{\selectrandomly} %\cmddef{selectrandomly}\verb|{|\meta{filename}\verb/}{/\meta{n}\verb!}!\\[10pt] %The command \cmdname{selectrandomly} will select \meta{n} %problems that are defined in the file \meta{filename}. Each %problem is proceeded by %\DescribeMacro{\PSNitem}\cmddef{PSitem} which is %defined to be \cmdname{item}, so the command %\cmdname{selectrandomly} should occur within one of the %list-like environments, such as \texttt{enumerate}. %For example: %\begin{verbatim} %\begin{enumerate} %\selectrandomly{easy.tex}{4} %\end{enumerate} %\end{verbatim} %will result in four numbered problems, selected at random %from the file \texttt{easy.tex}. (The \texttt{.tex} extension %may be omitted.) Each problem is followed by the command %\cmddef{endPSNitem} which by default does nothing. % %Multiple \cmdname{selectrandomly} commands may be used, however a %different file must be used each time. For %example: %\begin{verbatim} %\begin{enumerate} %\item Differentiate the following functions with respect to $x$: % %\begin{enumerate} %\selectrandomly{samples/easy.tex}{3} %\selectrandomly{samples/args.tex}{1} %\end{enumerate} % %\selectrandomly{samples/implicit.tex}{1} %\selectrandomly{samples/1stprncpl.tex}{1} % %\end{enumerate} %\end{verbatim} %This will result in a total of 6 problems, numbered 1(a), %1(b), 1(c), 1(d), 2 and 3. % %If a randomly selected problem requires arguments, a message %similar to the following will be displayed: %\begin{verbatim} %Problem diff:quad requires 3 argument(s), please specify (e.g. {5}{3}): %\end{verbatim} %Enter the required arguments, where each argument is %enclosed in braces (\{ \}). % %\section{Other Commands} %\DescribeMacro{\PSNrandseed} %The command \cmddef{PSNrandseed}\verb|{|\meta{n}\verb/}/ specifies %the seed for the random number generator. For example, %if you are using \cmdlink{selectrandomly}, %\verb|\PSNrandseed{\year}| will produce a different set of %problems each year, whereas \verb|\PSNrandseed{\time}| %will produce a different set of problems each time you %\LaTeX\ the problem sheet (as long as you leave at least a %minute between runs.) % %\DescribeMacro{\random} %The command \cmddef{random}\verb|{|\meta{counter}\verb/}{/\meta{a}\verb!}{!\meta{b}\verb-}- %generates a random number from \meta{a} to \meta{b} and %stores it in the \LaTeX\ counter \meta{counter}. For example, %to select 2, 3 or 4 problems from the file %\texttt{implicit.tex}: %\begin{verbatim} %\newcounter{numproblems} %\begin{enumerate} %\random{numproblems}{2}{4} %\selectrandomly{implicit.tex}{\value{numproblems}} %\end{enumerate} %\end{verbatim} %(Note the use of \cmdname{value}.) % %This command can also be used to generate random values for %problems that take arguments. Consider the problem \probref{diff:quad} %defined earlier. Three counters can be defined to represent the %three coefficients: %\begin{verbatim} %\newcounter{A} %\newcounter{B} %\newcounter{C} %\end{verbatim} %Random values can now be assigned to these counters: %\begin{verbatim} %\random{A}{-5}{5} %\random{B}{-5}{5} %\random{C}{-5}{5} %\end{verbatim} %Finally, the problem can be used (note the use of \cmdname{arabic}): %\begin{verbatim} %\useproblem{diff:quad}{\arabic{A}}{\arabic{B}}{\arabic{C}} %\end{verbatim} % %\DescribeMacro{\doforrandN}% %The command %\cmddef{doforrandN}\verb|{|\meta{n}\verb/}{/\meta{cmd}\verb!}{!\meta{list}\verb+}{+\meta{text}\verb-}- will apply %\meta{text} for a random selection of \meta{n} items in the %comma separated \meta{list}. In each iteration the list %item is denoted by \meta{cmd}. For example, suppose you %have three files called \texttt{file1.tex}, %\texttt{file2.tex} and \texttt{file3.tex}, and you want to %select 1 problem from two of the three files, then you can %do: %\begin{verbatim} %\doforrandN{2}{\file}{file1,file2,file3}{\selectrandomly{\file}{1}} %\end{verbatim} %Note that it is also possible to do %\begin{verbatim} %\newcounter{numproblems} %\random{numproblems}{1}{3} %\selectrandomly{file\arabic{numproblems}}{1} %\random{numproblems}{1}{3} %\selectrandomly{file\arabic{numproblems}}{1} %\end{verbatim} %however there is a possibility that the same file may be %selected twice which will cause an error. % %\DescribeMacro{\showanswers} %The command \cmddef{showanswers} will show the solutions from %that point on. May be localised by placing within a group. % %\DescribeMacro{\hideanswers} %The command \cmddef{hideanswers} will hide the solutions from %that point on. May be localised by placing within a group. % %The solution is placed inside the \DescribeEnv{solution}\env{solution} %environment. By default this environment simply does %\verb|\par\noindent\textbf{\solutionname:} | at the start, where %\DescribeMacro{\solutionname}\cmddef{solutionname} %has the value: Solution. See the file \texttt{sample3.tex}, which %comes with this package, for an illustration of how to %customise the way in which the randomly selected problems are %displayed. This sample file randomly selects multiple choice %problems stored in the file \texttt{tabmchoice.tex}, and displays them %in a longtable \env{environment}. As from version 2.03, the package %will not define this environment if another package or class file has %already defined it. % %\DescribeMacro{showanswers} %The boolean variable \texttt{showanswers} is defined to be %true if the answers are shown and false otherwise. You can %therefore do something like: %\begin{verbatim} %\ifthenelse{\boolean{showanswers}}{\textbf{Solution Sheet}}{} %\end{verbatim} %and \textbf{Solution Sheet} will be printed only if the %answers are displayed. (For more information on %\cmdname{ifthenelse} and \cmdname{boolean} see the %documentation for the \texttt{ifthen} package by %David Carlisle.) % %The \texttt{showanswers} switch can also be used within the definition %of a problem, if you want the question to appear differently if the %solution is displayed. For example: %\begin{verbatim} %\newproblem{mc:prod}{% %Which of the following is the derivative of $x\sin(x)$? %(Circle the correct answer.) %\ifthenelse{\boolean{showanswers}}{}% %{\begin{description} %\item[A] $\sin(x)$ %\item[B] $x\cos(x)$ %\item[C] $\sin(x) + x\cos(x)$ %\end{description} %}}{% %\begin{description} %\item[A] $\sin(x)$ %\item[B] $x\cos(x)$ %\item[\textcircled{C}] $\sin(x) + x\cos(x)$ (product rule). %\end{description} %} %\end{verbatim} %If the solutions are not displayed, the question will appear %as %\begin{description} %\item Which of the following is the derivative of %$x\sin(x)$? (Circle the correct answer.) %\begin{description} %\item[A] $\sin(x)$\item[B] $x\cos(x)$\item[C] $\sin(x) + x\cos(x)$\end{description} %\end{description} %otherwise it will appear as: %\begin{description} %\item Which of the following is the derivative of %$x\sin(x)$? (Circle the correct answer.) %\begin{description} %\item[A] $\sin(x)$\item[B] $x\cos(x)$\item[\textcircled{C}] $\sin(x) + x\cos(x)$ (product rule)\end{description} %\end{description} % %\section{Troubleshooting} %\subsection{Unexpected Output} %\begin{itemize} %\item I have lots of blank space before the first problem when %using \cmdlink{selectrandomly}. % %This is probably because you have lots of extraneous white space %in your database. \cmdlink{selectrandomly} will input the entire %file, so any extra space will be included. Try commenting out the %extra space using \%. %\end{itemize} % %\subsection{Error Messages} %\begin{itemize} %\item %\begin{ttfamily} %! Package probsoln Error: Label \ldots\ already used. %\end{ttfamily} % %Each label identifier used in \cmdlink{newproblem} must be %unique. Check to make sure you haven't used the same label %more than once. Also check to make sure you haven't %\cmdname{input}ed or randomly selected from the same file more %than once. (Or \cmdname{input}ed and randomly selected from %the same file.) % %\item %\begin{ttfamily} %! Package probsoln Error: Label \ldots\ undefined. %\end{ttfamily} % %You need to define a problem before you can use it. Check to %make sure you haven't mis-spelt it, and check to make sure you %have \cmdname{input}ed the file in which it is defined. % %\item %\begin{ttfamily} %! Package probsoln Error: Requested number too large. %\end{ttfamily} % %You have asked for more problems than are defined within the %specified file. All problems in that file will be selected. % %\item %\begin{ttfamily} %! Package probsoln Error: Can't randomly select \meta{n} %item(s) %\end{ttfamily} % %You have asked to randomly select \meta{n} items from a list %that has less than \meta{n} elements. For example, the %following will generate this error: %\begin{verbatim} %\doforrandN{10}{\file}{file1,file2,file3}{% %\selectrandomly{\file}{1}} %\end{verbatim} %In this case the list, \texttt{file1,file2,file3} has only 3 %elements, but the user has asked for 10 elements. If you type %`h' at the \LaTeX\ prompt it will tell you how many items it thinks %there are in the list. Remember that each item must be separated by a %comma. % %\item %\begin{ttfamily} %! LaTeX Error: Lonely \cmdname{item}--perhaps missing list %environment. %\end{ttfamily} % %Each problem selected using \cmdlink{selectrandomly} is %proceeded by \cmdlink{PSNitem} which by default is defined %as \cmdname{item}, and should therefore be %placed in one of the list environments, such as %\texttt{enumerate}. Alternatively, redefine \cmdlink{PSNitem}. % %\item I get an error when I put a command definition in my database %when using \cmdname{selectrandomly}. % %\cmdlink{selectrandomly} inputs the database twice, so any %command definition will be read twice, causing an error. You %can use the switch \cmdname{iffirstpass} to prevent the error. For %example: %\begin{verbatim} %\iffirstpass %\newcommand{\mycmd}{} %\fi %\end{verbatim} %It is generally not a good idea to put anything other than %\cmdlink{newproblem} commands within the database. % %\end{itemize} % %\section{Contact Details} %Dr Nicola Talbot\\ %School of Computing Sciences\\ %University of East Anglia\\ %Norwich. NR4 7TJ\\ %\url{http://theoval.cmp.uea.ac.uk/~nlct/} % %\StopEventually{\PrintIndex} % %\section{The Code} %\iffalse % \begin{macrocode} %<*probsoln.sty> % \end{macrocode} %\fi % At the start of the package, specify that the \LaTeXe\ format is % required. And specify the package provided. % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{probsoln}[2007/08/21 v2.04 Problems and their Solutions Package (NLCT)] \RequirePackage{ifthen} % \end{macrocode} % Define newif to determine whether or not to show the answers. % (Changed to |\provideboolean| 21 Mar 2004.) % \begin{macrocode} \provideboolean{showanswers} % \end{macrocode} %\begin{macro}{\showanswers} % \begin{macrocode} \let\showanswers=\showanswerstrue % \end{macrocode} %\end{macro} %\begin{macro}{\hideanswers} % \begin{macrocode} \let\hideanswers=\showanswersfalse % \end{macrocode} %\end{macro} % Now define the package options % \begin{macrocode} \DeclareOption{answers}{\showanswerstrue} \DeclareOption{noanswers}{\showanswersfalse} \ExecuteOptions{noanswers} \ProcessOptions % \end{macrocode} % Create newifs for selecting randomly and parsing through file % \begin{macrocode} \newif\ifselectrandom \selectrandomfalse \newif\iffirstpass \newif\ifselected % \end{macrocode} %\begin{macro}{\newproblem} % Define the command that creates a new problem. As from version % 2.03 this command now has a starred version for problems without % solutions. % \begin{macrocode} \newcommand{\newproblem}{\@ifstar\@snewproblem\@newproblem} % \end{macrocode} %\end{macro} %\begin{macro}{\@newproblem} % The unstarred version. % \begin{macrocode} \newcommand{\@newproblem}[4][0]{% \ifselectrandom \iffirstpass % on the first pass, just store the label, and increment \@probN \global\advance\@probN by 1 \expandafter\gdef\csname @problabel\romannumeral\@probN\endcsname{#2}% \else % check to see if this problem has been selected \checkselected{#2}% \ifselected \@ifundefined{@prob@#2}{% \ifnum#1=0 % this problem has no arguments \expandafter\gdef\csname @prob@#2\endcsname{% #3 \ifshowanswers\begin{solution}#4\end{solution}\fi}% \expandafter\gdef\csname @prob@#2@arg\endcsname{\relax}% \else \message{Problem #2 requires #1 argument(s), please specify (e.g. {5}{3}):}% \read-1to\@tmp \expandafter\xdef\csname @prob@#2@arg\endcsname{\@tmp}% \expandafter\global\expandafter\newcommand\csname @prob@#2\endcsname[#1]{% #3 \ifshowanswers\begin{solution}#4\end{solution}\fi}% \fi }{% \PackageError{probsoln}{Label #2 already used}% {Each problem must have a unique label identifier}% }% \fi \fi \else \@ifundefined{@prob@#2}{% \expandafter\global\expandafter\newcommand\csname @prob@#2\endcsname[#1]{% #3 \ifshowanswers\begin{solution}#4\end{solution}\fi}% }{% \PackageError{probsoln}{Label #2 already used}% {Each problem must have a unique label identifier}% } \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\@snewproblem} % The starred version (new to version 2.03). Note that there is one % less argument, because the problem doesn't have a solution. % \begin{macrocode} \newcommand{\@snewproblem}[3][0]{% \ifselectrandom \iffirstpass % on the first pass, just store the label, and increment \@probN \global\advance\@probN by 1 \expandafter\gdef\csname @problabel\romannumeral\@probN\endcsname{#2}% \else % check to see if this problem has been selected \checkselected{#2}% \ifselected \@ifundefined{@prob@#2}{% \ifnum#1=0 % this problem has no arguments \expandafter\gdef\csname @prob@#2\endcsname{#3}% \expandafter\gdef\csname @prob@#2@arg\endcsname{\relax}% \else \message{Problem #2 requires #1 argument(s), please specify (e.g. {5}{3}):}% \read-1to\@tmp \expandafter\xdef\csname @prob@#2@arg\endcsname{\@tmp}% \expandafter\global\expandafter\newcommand\csname @prob@#2\endcsname[#1]{#3}% \fi }{% \PackageError{probsoln}{Label #2 already used}% {Each problem must have a unique label identifier}% }% \fi \fi \else \@ifundefined{@prob@#2}{% \expandafter\global\expandafter\newcommand\csname @prob@#2\endcsname[#1]{#3}% }{% \PackageError{probsoln}{Label #2 already used}% {Each problem must have a unique label identifier}% } \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\useproblem} % Define the command that uses a problem % \begin{macrocode} \newcommand*{\useproblem}[1]{% \@ifundefined{@prob@#1}{% \PackageError{probsoln}{Label #1 undefined}% {Can't find problem defined with label identifier `#1'}% }{\csname @prob@#1\endcsname}% } % \end{macrocode} %\end{macro} % Now deal with the stuff for random selection. % First define some registers for later use. % \begin{macrocode} \newcount\@probN \newcount\@probselN \newcount\@rndselctr \newcount\r@ndcur \newcount\@ps@randtmp \r@ndcur=1\relax % \end{macrocode} %\begin{macro}{\PSNrandseed} % Set the random generator seed % \begin{macrocode} \newcommand*{\PSNrandseed}[1]{% \ifnum#1=0\relax \PackageWarning{probsoln}{Can't have 0 as random seed, changing to 1}% \r@ndcur=1\relax \else \r@ndcur=#1\relax \fi \PackageInfo{probsoln}{Random Seed = \number\r@ndcur}% } % \end{macrocode} %\end{macro} %\begin{macro}{\PSNrand} % Generate a random integer. % \begin{macrocode} \newcommand*{\PSNrand}{% \@ps@randtmp=\r@ndcur \multiply\@ps@randtmp by 16807\relax \r@ndcur=\@ps@randtmp \divide\r@ndcur by 120001\relax \multiply\r@ndcur by 120001\relax \advance\@ps@randtmp by -\r@ndcur \r@ndcur = \@ps@randtmp \ifnum\r@ndcur=0\relax\r@ndcur=1\fi } % \end{macrocode} %\end{macro} %\begin{macro}{\PSNrandom} % \cs{PSNrandom}\marg{count}\marg{n} stores a random number % from 1 to \meta{n} % in the TeX count register \meta{count} % \begin{macrocode} \newcommand{\PSNrandom}[2]{% % \end{macrocode} % generate new random number. % \begin{macrocode} \PSNrand #1=\r@ndcur \@ps@randtmp=\r@ndcur % \end{macrocode} % now set \meta{count} to (\meta{count} mod \meta{n}) + 1 % \begin{macrocode} \divide\@ps@randtmp by #2\relax \multiply\@ps@randtmp by #2\relax \advance#1 by -\@ps@randtmp \advance#1 by 1\relax } % \end{macrocode} %\end{macro} %\begin{macro}{\random} % \cs{random}\marg{counter}\marg{a}\marg{b}: % Generate a random number in the range $[a,b]$, and store this % number in the \LaTeX\ counter \meta{counter}. % \begin{macrocode} \newcommand{\random}[3]{% \ifnum#2=1\relax \PSNrandom{\value{#1}}{#3}% \else \@rndselctr=#3% \advance\@rndselctr by -#2\relax \advance\@rndselctr by 1\relax \PSNrandom{\value{#1}}{\@rndselctr}% \addtocounter{#1}{#2}% \addtocounter{#1}{-1}% \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\selectallproblems} % Define command to use all problems from a given file. % Syntax: \cs{selectallproblems}\marg{filename}. % \begin{macrocode} \newcommand*{\selectallproblems}[1]{% \global\@probN=0\relax \selectrandomtrue \firstpasstrue \input{#1}% \firstpassfalse \selectrandomfalse \input{#1}% \global\@rndselctr=1\relax \whiledo{\@rndselctr < \@probN \TE@or \@rndselctr = \@probN}{% \edef\@tmp{\csname @problabel\romannumeral\@rndselctr\endcsname}% \edef\@probargs{{\@tmp}\csname @prob@\@tmp @arg\endcsname}% \PSNitem \expandafter\useproblem\@probargs \endPSNitem \global\advance\@rndselctr by 1\relax }} % \end{macrocode} %\end{macro} %\begin{macro}{\selectrandomly} % Now define command to randomly select \meta{n} problems from % a given file. % Syntax: \cs{selectrandomly}\marg{filename}\meta{n}. % \begin{macrocode} \newcommand*{\selectrandomly}[2]{% \global\@probselN=#2\relax \global\@probN=0\relax \selectrandomtrue \firstpasstrue \input{#1}% \ifnum\@probselN>\@probN \PackageError{probsoln}{Requested number too large}% {You have asked for \the\@probselN \space problems, but there are only \the\@probN \space problems defined in the file #1. I will only select \the\@probN \space problems.}% \global\@probselN=\@probN \fi \shuffle{@problabel}{\@probN}% \firstpassfalse \input{#1}% \selectrandomfalse \global\@rndselctr=1\relax \whiledo{\@rndselctr < \@probselN \TE@or \@rndselctr = \@probselN}{% \edef\@tmp{\csname @problabel\romannumeral\@rndselctr\endcsname}% \edef\@probargs{{\@tmp}\csname @prob@\@tmp @arg\endcsname}% \PSNitem \expandafter\useproblem\@probargs \endPSNitem \global\advance\@rndselctr by 1\relax }% } % \end{macrocode} %\end{macro} %\begin{macro}{\PSNitem} % What to do at start and end of each randomly selected item: % (I may turn this into a normal environment at a later date. At the % moment, I have kept \verb|\PSNitem| for compatibility with earlier % versions.) % \begin{macrocode} \newcommand*{\PSNitem}{\item} \@ifundefined{endPSNitem}{\def\endPSNitem{}}{% \PackageError{probsoln}{\string\endPSitem\ already defined}{}} % \end{macrocode} %\end{macro} %\begin{macro}{\solutionname} % How to display each solution % \begin{macrocode} \providecommand*{\solutionname}{Solution} \@ifundefined{solution}{% \newenvironment{solution}{\par\noindent\textbf{\solutionname:} }{}}{% } % \end{macrocode} %\end{macro} %\begin{macro}{\checkselected} % Check to see if label has been selected % \begin{macrocode} \newcount\@ckselctr \newcommand*{\checkselected}[1]{% \selectedfalse \@ckselctr=1\relax \whiledo{\@ckselctr < \@probselN \TE@or \@ckselctr = \@probselN}{% \ifthenelse{\equal{#1}{\csname @problabel\romannumeral\@ckselctr\endcsname}}% {\global\selectedtrue \global\@ckselctr=\@probselN}{}% \advance\@ckselctr by 1\relax }% } % \end{macrocode} %\end{macro} %\begin{macro}{\shuffle} % Shuffle contents of pseudo-array. For example, suppose you have % the following definitions: |\def\fooi{A}|, |\def\fooii{B}| and % |\def\fooiii{C}|, then |\shuffle{foo}{3}| will shuffle the % definitions, so you may end up with, e.g.\ |\def\fooi{C}|, % |\def\fooii{A}|, |\def\fooiii{B}|, or some other variation. % \begin{macrocode} \newcount\@shfctr \newcount\@shfA \newcount\@shfB \newcommand{\shuffle}[2]{% \@shfctr=1\relax \whiledo{\@shfctr < 101}{% \PSNrandom{\@shfA}{#2}\PSNrandom{\@shfB}{#2}% \ifnum\@shfA=\@shfB \else \edef\@@tmpA{\csname#1\romannumeral\@shfA\endcsname}% \let\@tmpA=\@@tmpA \edef\@@tmpB{\csname#1\romannumeral\@shfB\endcsname}% \let\@tmpB=\@@tmpB \expandafter\xdef\csname#1\romannumeral\@shfA\endcsname{\@tmpB}% \expandafter\xdef\csname#1\romannumeral\@shfB\endcsname{\@tmpA}% \fi \advance\@shfctr by 1\relax }% } % \end{macrocode} %\end{macro} %\begin{macro}{\doforrandN} % Syntax: \cs{doforrandN}\marg{n}\marg{cmd}\marg{list}\marg{text}. % A bit like |\@for| but only for a random subset of the given list. % For example, %\begin{verbatim} %\doforrandN{2}{\tmp}{file1,file2,file3}{% %\selectrandomly{\tmp}{1}} %\end{verbatim} %This will select one problem each from two out of the three listed %files. % \begin{macrocode} \newcount\@ps@forrand \newcommand{\doforrandN}[4]{% {\@ps@forrand=0\relax \@for#2:=#3\do{% \advance\@ps@forrand by 1\relax \expandafter\edef\csname @doforrandN@\romannumeral\@ps@forrand\endcsname{#2}}% \ifnum\@ps@forrand<#1\relax \PackageError{probsoln}{Can't randomly select \number#1 item(s)}{You have requested \number#1 item(s), but there are only \number\@ps@forrand item(s) in the list}% \else \shuffle{@doforrandN@}{\@ps@forrand}% \ifnum#1>0\relax \@ps@forrand=0\relax \loop \advance\@ps@forrand by 1\relax \edef#2{\csname @doforrandN@\romannumeral\@ps@forrand\endcsname}% #4% \ifnum\@ps@forrand<#1\relax \repeat \fi \fi }} % \end{macrocode} %\end{macro} %\iffalse % \begin{macrocode} % % \end{macrocode} %\fi %\Finale \endinput