%\def\filedate{21 Mar 2004} %\def\fileversion{2.0} %\def\filename{probsoln.dtx} %\def\docdate{19th Dec 2000} %\iffalse % Doc-Source file to use with LaTeX2e % Copyright (C) 2000 Nicola Talbot, all rights reserved. %\fi % % \newsavebox{\syntaxbox} % \newenvironment{syntax}{\begin{lrbox}{\syntaxbox}\ttfamily}% %{\end{lrbox}\par\noindent\fbox{\usebox{\syntaxbox}}\\} % \title{probsoln.sty v\fileversion: \LaTeX\ Package to help create problem sheets} % \author{N.L.C. Talbot} % \date{\docdate} % \maketitle % \tableofcontents % % \section{Introduction} % The package |probsoln.sty| 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: % % \centerline{% % \begin{tabular}{@{\ttfamily}ll} % answers & Show the answers\\ % noanswers & Don't show the answers (default) % \end{tabular} % } % % \section{Commands Provided} % \subsection{Creating a New Problem} % \begin{syntax}|\newproblem[|\meta{nargs}|]{|\meta{label}|}{|\meta{problem}|}{|\meta{solution}|}|\end{syntax} % \DescribeMacro{\newproblem} % A new problem is defined using the command |\newproblem|. This does not print anything, % but merely stores the problem. 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: %\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 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 refered to by |#1|, |#2|, \ldots, |#9|. % For example, the following problem takes one parameter: %\begin{verbatim} %\newproblem[1]{sindiff}{% %\(f(x) = \sin(#1x)\) %}{% %\(f'(x) = #1\cos(#1x)\) %} %\end{verbatim} % % The |quaddiff| problem shown above can be made more generic by using parameters: %\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. % % To generate a database, simply create a |.tex| file where all the problems % are defined using |\newproblem|, and either |\input| it at the % start of your document if you want to use specific problems % (see Section~\ref{sec:useprob}), or % pass it to |\selectrandomly| (see Section~\ref{sec:selran}). % % \subsection{Displaying a Problem} % \label{sec:useprob} % \begin{syntax}|\useproblem{|\meta{label}|}|\end{syntax} % \DescribeMacro{\useproblem} % Once a problem has be defined using |\newproblem|, it can be typeset % using the command |\useproblem|. If the problem was defined to take % arguments, the arguments to the problem should come after the % label. In the case of the |sindiff| example above, the command % |\useproblem{sindiff}{2}| would produce the following:\\[10pt] % \(f(x) = \sin(2x)\) % \paragraph{Solution:} \(f'(x) = 2\cos(2x)\)\\[10pt] % whereas the command |\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 |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 |answers| %to the |probsoln| package. % % \subsection{Selecting Problems at Random} % \label{sec:selran} % \begin{syntax}|\selectrandomly{|\meta{filename}|}{|\meta{n}|}|\end{syntax} % \DescribeMacro{\selectrandomly} % The command |\selectrandomly| will select \meta{n} problems that are defined % in the file \meta{filename}. Each problem is preceeded by a |\item|, so the % command |\selectrandomly| should occur within one of the list-like environments, % such as |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 |easy.tex|. (The \texttt{.tex} extension may be omitted.) % % Multiple |\selectrandomly| commands may be used. 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 (\{ \}). % % \subsection{Other Commands} % \DescribeMacro{\PSNrandseed} % The command |\PSNrandseed{|\meta{n}|}| specifies the seed for the random % number generator. For example, |\PSNrandseed{\year}| will produce a % different set of random problems each year, whereas |\PSNrandseed{\time}| % will produce a different set of problems each time you \LaTeX\ the % problem (as long as you leave at least a minute between runs.) % % \DescribeMacro{\showanswers} % The command |\showanswers| will show the solutions from that point % on. May be localised by placing within a group. % % \DescribeMacro{\hideanswers} % The command |\hideanswers| will hide the solutions from that point % on. May be localised by placing within a group. % % \DescribeMacro{\solutionname} % By default, the solution is preceeded by the text: \textbf{Solution:}. This can % be changed by redefining the macro |\solutionname|. % % \DescribeMacro{showanswers} % The boolean variable |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 |\ifthenelse| and |\boolean| see the %documentation for the |ifthen| package by David Carlisle.) % % \section{Error Messages} %\begin{ttfamily} %! Package probsoln Error: Label \ldots\ already used. %\end{ttfamily}\\[10pt] % Each label identifier used in |\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 |\input|ed or randomly selected % from the same file more than once. (Or |\input|ed and randomly % selected from the same file.) %\\[10pt] %\begin{ttfamily} %! Package probsoln Error: Label \ldots\ undefined. %\end{ttfamily}\\[10pt] % You need to define a problem before you can use it. Check to % make sure you haven't mis-spelt it. %\\[10pt] %\begin{ttfamily} %! Package probsoln Error: Requested number too large. %\end{ttfamily} %\\[10pt] % You have asked for more problems than are defined within % the specified file. All problems in that file will be selected. % %\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{} % \section{The Code} % \iffalse % First we have the driver to get the documentation % \begin{macrocode} %<*driver> \documentclass{ltxdoc} \usepackage[colorlinks,bookmarks]{hyperref} \begin{document} \OnlyDescription \DocInput{probsoln.dtx} \end{document} % % \end{macrocode} % \fi % At the start of the package, specify that the \LaTeX2e format is % required. And specify the package provided. % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{probsoln}[2004/03/21 Problems and their Solutions Package] \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} \newcommand{\showanswers}{\showanswerstrue} \newcommand{\hideanswers}{\showanswersfalse} % \end{macrocode} % Now define the package options % \begin{macrocode} \DeclareOption{answers}{\showanswerstrue} \DeclareOption{noanswers}{\showanswersfalse} \ExecuteOptions{noanswers} \ProcessOptions % \end{macrocode} % Create a newif to determine whether a command has already been defined % \begin{macrocode} \newif\ifdefined \def\checkdefined#1{\ifx#1\relax \definedfalse \else \definedtrue \fi} % \end{macrocode} % Create newifs for selecting randomly and parsing through file % \begin{macrocode} \newif\ifselectrandom \selectrandomfalse \newif\iffirstpass \newif\ifselected % \end{macrocode} % Define the command that creates a new problem % \begin{macrocode} \newcommand{\solutionname}{Solution:} \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 \expandafter\checkdefined\csname @prob@#2\endcsname \ifdefined \PackageError{probsoln}{Label #2 already used}% {Each problem must have a unique label identifier} \else \ifnum#1=0 % this problem has no arguments \expandafter\newcommand\csname @prob@#2\endcsname[#1]{% #3 \ifshowanswers\paragraph{\solutionname} #4\fi} \else \message{Problem #2 requires #1 argument(s), please specify (e.g. {5}{3}):} \read-1to\@tmp \expandafter\let\csname @prob@#2@arg\endcsname=\@tmp \expandafter\newcommand\csname @prob@#2\endcsname[#1]{% #3 \ifshowanswers\paragraph{\solutionname} #4\fi} \fi \fi \fi \fi \else \expandafter\checkdefined\csname @prob@#2\endcsname \ifdefined \PackageError{probsoln}{Label #2 already used}% {Each problem must have a unique label identifier} \else \expandafter\newcommand\csname @prob@#2\endcsname[#1]{% #3 \ifshowanswers\paragraph{\solutionname} #4\fi} \fi \fi } % \end{macrocode} % Define the command that uses a problem % \begin{macrocode} \newcommand{\useproblem}[1]{% \expandafter\checkdefined\csname @prob@#1\endcsname \ifdefined \def\doprob{\csname @prob@#1\endcsname} \else \PackageError{probsoln}{Label #1 undefined}% {Can't find problem defined with label identifier '#1'} \def\doprob{\relax} \fi \doprob } % \end{macrocode} % Now deal with the stuff for random selection. % Syntax: |\selectrandomly{|\meta{filename}|}{|\meta{n}|}|. % \begin{macrocode} \newcount\@probN \newcount\@probselN \newcount\@rndselctr % \PSNrandom{}{} stores a random number from 1 to % in the TeX count register \newcount\r@ndcur \r@ndcur=1\relax \newcommand{\PSNrandseed}[1]{% \ifnum#1=0 \typeout{Can't have 0 as random seed, changing to 1} \r@ndcur=1\relax \else \r@ndcur=#1\relax \fi \typeout{Random Seed = \the\r@ndcur} } \newcount\@ps@randtmp \newcommand{\PSNrand}{ \@ps@randtmp=\r@ndcur \multiply\@ps@randtmp by 16807\relax \r@ndcur=\@ps@randtmp \divide\r@ndcur by 120001 \multiply\r@ndcur by 120001 \advance\@ps@randtmp by -\r@ndcur \r@ndcur = \@ps@randtmp \ifnum\r@ndcur=0\relax\r@ndcur=1\fi } \newcommand{\PSNrandom}[2]{% % generate new random number. \PSNrand #1=\r@ndcur \@ps@randtmp=\r@ndcur % now (#1 mod #2) + 1 \divide\@ps@randtmp by #2\relax \multiply\@ps@randtmp by #2\relax \advance#1 by -\@ps@randtmp \advance#1 by 1\relax } \newcommand{\selectrandomly}[2]{% \global\@probselN=#2 \global\@probN=0 \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 \@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} \item \expandafter\useproblem\@probargs \advance\@rndselctr by 1\relax } } % \end{macrocode} % 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} % Shuffle contents of pseudo-array % \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} %\Finale \endinput