% \iffalse meta-comment % % `examz' --- 2023/06/07 Version 1.0.0 % % Copyright (C) 2023 by Christopher McClain % E-mail: christopher.mcclain@mail.wvu.edu % ----------------------------------------- % % This file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either % version 1.3c 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.3 or later is part of all distributions of % LaTeX version 2008 or later. % % \fi % % \iffalse %<*driver> \ProvidesFile{examz.dtx} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesClass{examz} %<*class> [2023/06/07 v1.0.0 Randomized exams with multiple versions] % % %<*driver> \documentclass{ltxdoc} \usepackage[numbered]{hypdoc} \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{examz.dtx} \end{document} % % \fi % % \changes{v1.0.0}{2023/06/07}{First public release} % % \GetFileInfo{examz.dtx} % % \DoNotIndex{\addtocounter,\arabic,\AtBeginDocument,\AtEndDocument,\begin, % \BODY,\boolfalse,\booltrue,\chk@incompi,\clearcounterprefix, % \Collect@Body,\counterprefix,\CurrentOption,\DeclareOption, % \decr@latest@ques,\end,\endcoverpages,\find@latestques,\ifbool, % \ifnumequal,\ifnumless,\ifnumodd,\ifrandomizectr,\input, % \inputcountersfile,\LoadClass,\newbool,\newcommand,\newcounter, % \NewEnviron,\newenvironment,\newpage,\noprintanswers, % \norandomizectr,\notbool,\null,\opencountersfile,\parts, % \PassOptionsToClass,\printanswers,\ProcessOptions,\question, % \questions,\randomizectr,\refto@index,\relax,\renewcommand, % \RequirePackage,\savecounter,\setcounter,\setcounterprefix, % \setup@point@toks,\space,\subparts,\subsubparts,\thispagestyle, % \typein,\typeout,\value,\whileboolexpr,\xpatchcmd, % \xrandprovidecounter,\xvalue,\hrulefill,\makebox,\EnterResponse, % \NumberOfVersions,\endinput} % % \title{^^A % The \textsf{examz} class\thanks{^^A % This file describes version \fileversion, last revised \filedate.^^A % }^^A % } % \author{^^A % Christopher McClain\thanks{E-mail: christopher.mcclain@mail.wvu.edu}^^A % } % % \date{Released \filedate} % % \maketitle % %\begin{abstract} % The \textsf{examz} document class builds on the \textsf{exam} document class % that was developed by Philip S. Hirschhorn. An author may use the class % exactly as the \textsf{exam} class, but there are also additional features. % The document class facilitates the writing of questions with random elements, % the creation of multiple versions of an exam, and the use of separate files % as question banks. %\end{abstract} % %\tableofcontents % %\section{Introduction} % %\subsection{About} % % Since 1994, Philip Hirschhorn's \textsf{exam} document class has provided % authors and educators with a framework for writing exams that is both highly % customizable and easy to use. The \textsf{examz} document class loads the % \textsf{exam} class and adds some more features. Most of these new features % require the \textsf{counterz} package. % % First of all, the \textsf{examz} class may be loaded with new options that % facilitate the use of commands from the \textsf{counterz} package for writing % questions with random elements. Second, a new \textsf{versions} environment % allows for the creation of multiple versions of an exam in the same document, % alternating between exams and solutions, if desired. Third, the command % \cs{question} may now be replaced by the command \cs{questionfrombank} which % allows for random selection of questions from a user-defined question bank. % Finally, a few simple macros make it even easier to modify the customized % content in headers, footers, and special pages when creating new exams from % previous documents. % % Some commands in \textsf{exam} have been patched in order to distinctly label % the questions in different exam versions and their solutions (so that \LaTeX{} % issues no warnings about multiply-defined labels). The optional environment % \textsf{coverpages} has also been patched for two-sided documents so that the % subsequent odd arabic numerals always appear on the front pages. % %\subsection{License} % % Copyright \copyright\ 2023 Christopher McClain. This software may be copied, % distributed, and/or modified under the %terms of the % \href{https://www.latex-project.org/lppl/}{LaTeX Project Public License}, % either version 1.3c of this license or any later version. % %\subsection{Installation} % % Run \LaTeX{} on examz.ins to generate the file examz.cls, and copy it to % your local texmf directory. Run (pdf)\LaTeX{} on examz.dtx to generate the % documentation examz.pdf. Typesetting the documentation requires the package % \textsf{hypdoc} which is included in \TeX\ distributions and at % \href{http://www.ctan.org} {The Comprehensive TeX Archive Network}. % %\section{User Guide} % % To use this document class, begin your document with the following line: % %\begin{verbatim} %\documentclass{examz} %\end{verbatim} % % \noindent % This document class loads the \textsf{exam} class and admits the options for % that class. See the documentation for the \textsf{exam} class for details. The % \textsf{examz} class also admits the additional options \textsf{randomize}, % \textsf{norandomize}, \textsf{prompt}, and \textsf{complete}, all of which are % discussed in this guide. This document class requires the \textsf{counterz} % package, which is available at \href{http://www.ctan.org} % {The Comprehensive TeX Archive Network}. % % In addition to its parent class \textsf{exam} and the \textsf{counterz} % package, the \textsf{examz} class requires the following packages: % \textsf{xparse}, \textsf{environ}, \textsf{etoolbox}, and \textsf{makecmds} % (the latter two via \textsf{counterz}), all of which are included in most % standard \TeX\ distributions and at \href{http://www.ctan.org}{The % Comprehensive TeX Archive Network}. % %\subsection{Randomized Exams}\label{usr:versions} % % The \textsf{examz} class loads the \textsf{counterz} package which provides % commands for generating, saving, recalling, manipulating, and displaying % random values for counters. These commands may be incorporated into questions % to generate random exams. The process of saving and recalling counters may be % explicitly coded in the document, as described in the \textsf{counterz} % package documentation, but the \textsf{examz} class may instead be loaded with % options to automate this process. % % Loading the class with the option \textsf{randomize} will execute the commands % \cs{randomizectr} and \cs{opencountersfile} from the \textsf{counterz} % package. Loading the class with the option \textsf{norandomize} will execute % the commands \cs{norandomizectr} and \cs{inputcountersfile}. If neither of % these options are loaded, the default behavior is that of the option % \textsf{randomize}. The reason for this is that if the document contains no % randomly generated counters then this default choice will have no effect % anyway, and if the document does contain randomly generated counters then the % first typesetting must generate these counter values. % % A third option \textsf{prompt} frees the user from the burden of manually % changing between \textsf{randomize} and \textsf{nonrandomize} and also % protects against accidental overwriting of previously generated counter % values. This option will execute the command \cs{promptrandomexam}, which % is an instance of the command \cs{promptrandomizectr} from the % \textsf{counterz} package, followed by one of the commands % \cs{opencountersfile} or \cs{inputcountersfile} as appropriate. The terminal % dialogue of \cs{promptrandomexam} can be changed with the use of % \cs{renewcommand}, if desired. (See Section \ref{imp} for the implementation % of \cs{promptrandomexam}.) There are additional effects from this option with % regard to the \textsf{versions} environment, described below. % % \DescribeEnv{versions} % The \textsf{versions} environment uses a loop and a counter \textit{version} % to generate versions of the exam, incrementing the counter and updating the % page numbers along the way. The version number may be displayed in headers or % elsewhere with either \cs{theversion} or \cs{arabic}\{version\}. The % environment takes an optional argument: the number of desired versions, with % 1 being the default value. The environment is used as follows: % %\begin{verbatim} %\begin{versions}[] % %\end{versions} %\end{verbatim} % %\noindent % where \textit{exam content} refers to the \textsf{questions} environment (as % defined in the \textsf{exam} package), cover pages, and anything else after % \cs{begin}\{document\} that is intended to appear in the exam. When the class % is randomized with the option \textsf{prompt}, the number provided by the % optional argument is not used, and so there is no reason to include it. % Instead, a command \cs{promptversions} inputs the number of versions using a % terminal dialogue. (The dialogue can be changed by using \cs{renewcommand}, % if desired. See Section \ref{imp:versions} for the implementation of % \cs{promptversions}.) When the exam is not randomized, the number of versions % is inputted from the previously generated counters file, and so the prompt % does not appear. % % Recall that the \textsf{examz} class inherits the options \textsf{answers} % and \textsf{noanswers} from the \textsf{exam} class. The \textsf{examz} class % also has an additional option called \textsf{complete}. When loaded with this % option, the document alternately prints without and with solutions. (Note: % This feature only takes effect when using the \textsf{versions} environment.) % Moreover, when the class is loaded with the option \textsf{twoside} (inherited % from its grandparent class \textsf{article}), an extra blank page is inserted % at the end of each exam when necessary to ensure that the next exam starts on % a front page. An exam that begins with the line % %\begin{verbatim} %\documentclass{11pt,twoside,addpoints,prompt,complete} %\end{verbatim} % %\noindent % and uses the \textsf{versions} environment, for example, will ask the user % whether to randomize, and if so, how many versions to print. Then the typeset % document will include the requested number of versions, alternating between % exams and solutions, with correct grade tables and no warnings about % multiply-defined labels, and an extra blank page whenever an exam has an odd % number of pages. % %\subsection{Question Banks}\label{usr:banks} % % Within the \textsf{questions} environment, the \textsf{examz} package offers % an alternative to the command \cs{question} that allows for the random % selection of a question from a question bank. The command % \DescribeMacro{\questionfrombank} % \cs{questionfrombank}\oarg{points}\marg{filename} has two arguments, the first % of which is optional. The first (optional) argument is the point value of the % question, just as with the command \cs{question} from the \textsf{exam} class. % The second argument is the name of a \TeX{} file (without the .tex extension). % The second argument may include a path. Suppose, for example, that the % directory which contains the main exam document \textsf{Test1.tex} also % contains a subdirectory named \textsf{Problems} containing the files % \textsf{Solve\_Linear\_Equation.tex} and \textsf{State\_Capitals.tex}. Then % the code % % %\begin{verbatim} %\documentclass{examz} %\begin{document} %\begin{questions} % \questionfrombank{Problems/Solve_Linear_Equation} % \questionfrombank{Problems/State_Capitals} %\end{questions} %\end{document} %\end{verbatim} % %\noindent % generates an exam with two questions, one randomly selected from each of the % two specified files. % % When several files are contained in the same directory, the repetition of the % \DescribeMacro{\setquestionpath} % path name can be reduced by the command \cs{setquestionpath}\marg{path name}, % as illustrated by the following code: % %\begin{verbatim} %\documentclass{examz} %\begin{document} % \setquestionpath{Problems/} %\begin{questions} % \questionfrombank{Solve_Linear_Equation} % \questionfrombank{State_Capitals} %\end{questions} %\end{document} %\end{verbatim} % % \noindent % The command \cs{setquestionpath} can be used both inside and outside of the % \textsf{questions} environment, and can be used to change the path multiple % times, if desired. % % In order for a file to function as a question bank, it must conform to a % specific (but very simple) structure. First of all, every question bank file % begins with a command \cs{setnumberofquestions}\marg{number}. Second, all of % \DescribeMacro{\setnumberofquestions} % the questions are contained within a \textsf{questionbank} environment. Third, % each individual question is contained within a \textsf{qbitem} environment. % This structure is exhibited by the following code, which could be the entire % contents of a file \textsf{State\_Capitals.tex} inputted by the command \cs{questionfrombank}: % %\begin{verbatim} %\setnumberofquestions{2} %\begin{questionbank} %\begin{qbitem}{1} % What is the capital of Maine? %\end{qbitem} %\begin{qbitem}{2} % What is the capital of Nebraska? %\end{qbitem} %\end{questionbank} %\end{verbatim} % % \DescribeEnv{questionbank} % The \textsf{questionbank} environment randomly generates an integer between 1 % and the number specified in the preceding command \cs{setnumberofquestions}. % Each instance of the environment \textsf{qbitem}\marg{item number} compares % \DescribeEnv{qbitem} % its numerical argument \meta{item number} to this randomly generated number % and executes the environment's body of content only if the numbers match. Then % the \textsf{questionbank} environment ends input so that nothing in the file % after that environment will be included. Note that neither environment % includes within its body the \cs{question} command; that command is already % part of the command \cs{questionfrombank} which inputs the file. Also note % that \cs{questionfrombank} sets the counter prefix to include the file name % and exam version number, so authors should use the prefix versions of counters % commands (e.g. \cs{xprovidecounter}, \cs{xarabic}, etc.) within % \textsf{qbitem} environments. (See the \textsf{counterz} documentation for % details.) % % The \textsf{qbitem} environment allows for the inclusion of the various % environments for parts and solutions that are provided by the \textsf{exam} % class. Recall that each of the six solutions environments admits an argument % to specify the amount of solution space. (The argument is optional for all % except \textsf{solutionbox}. See the \textsf{exam} documentation for details.) % The \textsf{examz} class offers a command \cs{setsolutionspace}\marg{length} % \DescribeMacro{\setsolutionspace} and six analogous solutions environments % that pass \meta{length} to their \textsf{exam} counterparts. For example, the % \DescribeEnv{qbsolution} % environment \textsf{qbsolution} is equivalent to the environment % \textsf{solution}\oarg{length}. The advantage of this is that the command % \cs{setsolutionspace}\marg{length} can be included once in the file, above the % \textsf{questionbank} environment, for example, and any subsequent adjustment % of the length can be done for all of the question bank items simultaneously % with a single edit rather than a comprehensive search and replace. Five other % environments \textsf{qbsolutionbox}, \textsf{qbsolutionorbox}, % \DescribeEnv{qbsolutionbox} % \textsf{qbsolutionorlines}, \textsf{qbsolutionordottedlines}, and finally % \DescribeEnv{qbsolutionorbox} % \textsf{qbsolutionorgrid} are similar analogues of the other \textsf{exam} % class solutions environments. Just as their \textsf{exam} counterparts, these % \DescribeEnv{qbsolutionorlines} % environments can also be used within the \textsf{parts} environment. The % \DescribeEnv{qbsolutionordottedlines} % command \cs{setsolutionspace} may be used multiple times in the same file, % \DescribeEnv{qbsolutionorgrid} % including within the \textsf{questionbank} environment, if necessary. % %\subsection{Customization Macros} % % The \textsf{exam} document class provides the means for customizing headers, % footers, special pages, etc. As an exam author makes changes to a document % between exams, courses, or academic terms, the author may require frequent % adjustment of certain standard content, such as the name of the exam or course % in a custom header. The \textsf{examz} document class offers several macros to % simplify such changes. For example, instead of explicitly including the text % ``MATH 101'' in a header, an author can use the macro \cs{coursename} which % can be set (and easily modified) at the beginning of the document. This is % especially useful when designing for many similar courses a custom % \textsf{.cls} file that loads the \textsf{examz} class and keeps the layout % and customizations ``behind the scenes''. We first list and describe these % macros and then provide an example of usage. % % \medskip % \noindent % \DescribeMacro{\instructorname} % The default replacement text for \cs{instructorname} is ``Instructor Name''. % % \noindent % \DescribeMacro{\setinstructorname} % Use the command \cs{setinstructorname}\marg{text} to change this text. % % \medskip % \noindent % \DescribeMacro{\coursename} % The default replacement text for \cs{coursename} is ``Course Name''. % % \noindent % \DescribeMacro{\setcoursename} % Use the command \cs{setcoursename}\marg{text} to change this text. % % \medskip % \noindent % \DescribeMacro{\examname} % The default replacement text for \cs{examname} is ``Exam Name''. % % \noindent % \DescribeMacro{\setexamname} % Use the command \cs{setexamname}\marg{text} to change this text. % % \medskip % \noindent % \DescribeMacro{\termname} % The default replacement text for \cs{termname} is ``Term Name''. % % \noindent % \DescribeMacro{\settermname} % Use the command \cs{settermname}\marg{text} to change this text. % % \medskip % \noindent % \DescribeMacro{\namespace} % The default expansion of \cs{namespace} is % ``Name:~\makebox[5cm]{\hrulefill}'' which is given by the code % \texttt{Name:$\sim$\cs{makebox}[5cm]\{\cs{hrulefill}\}}. % % \noindent % \DescribeMacro{\setnamespace} % Use the command \cs{setnamespace}\marg{format} to change this format. % % \medskip % \noindent %\DescribeMacro{\instructions} % The default replacement text for \cs{instructions} is ``Instructions Here''. % % \noindent % \DescribeMacro{\setinstructions} % Use the command \cs{setinstructions}\marg{text} to change this text, including % one or more paragraphs as needed. % % \medskip % \noindent % \DescribeMacro{\covernoanswers} % The command \cs{covernoanswers} can be used within the \textsf{coverpages} % environment provided by the \textsf{exam} class or simply as the first page(s) % of the exam. Its default expansion is empty. % \DescribeMacro{\setcovernoanswers} % Use the command \cs{setcovernoanswers}\marg{format} to change this format to % include special headers and footers, instructions, grade/point tables, an % instance of \cs{newpage}, etc. % % \medskip % \noindent % \DescribeMacro{\coveranswers} % The command \cs{coveranswers} can be used within the \textsf{coverpages} % environment provided by the \textsf{exam} class or simply as the first page(s) % of the exam. Its default expansion is \cs{covernoanswers}. % \DescribeMacro{\setcoveranswers} % Use the command \cs{setcoveranswers}\marg{format} to change this format to % include special headers and footers, instructions, grade/point tables, an % instance of \cs{newpage}, etc. % % \medskip % \noindent % \DescribeMacro{\printcover}% % The command \cs{printcover} executes either \cs{coveranswers} or % \cs{covernoanswers}, depending on the value of the boolean % \textsf{printanswers}. It can be used within the \textsf{coverpages} % environment that is provided by the \textsf{exam} class or simply as the first % page(s) of the exam. % % \medskip % \noindent %\DescribeMacro{\workspace} % The command \cs{workspace} is intended to provide additional work space on the % exam, perhaps at the end of the questions. Its default expansion is empty. Use % the command \cs{setworkspace}\marg{format} to add a bit of text, \cs{newpage}, % \DescribeMacro{\setworkspace} % or a custom header/footer. To include the content of \cs{workspace} only when % the boolean \textsf{printanswers} is FALSE, use the command % \DescribeMacro{\printworkspace} % \cs{printworkspace}. % % \medskip % One method of streamlining the work of developing many exams that use the same % layout and format is to write a simple \textsf{.cls} file to use as a custom % instantiation of the \textsf{examz} document class, perhaps even including % frequently used packages: % %\begin{verbatim} %\NeedsTeXFormat{LaTeX2e} %\ProvidesClass{MYexamz} %\DeclareOption*{\PassOptionsToClass{\CurrentOption}{examz}} %\ProcessOptions\relax %\LoadClass{examz} %\RequirePackage{mathtools,amssymb} %\pagestyle{headandfoot} %\header{\coursename}{\examname}{termname} %\setcovernoanswers{% % \namespace % % \bigskip % \instructions % % \bigskip % \gradetable % % \firstpagefooter{Version \arabic{version}}{}{} % \newpage %}% %\setworkspace{% % \newpage % \begin{center} Extra Work Space \end{center} % \newpage %}% %\endinput %\end{verbatim} % % \noindent % Then use the custom document class \textsf{MYexamz} for the exam: % %\begin{verbatim} %\documentclass[addpoints,prompt,complete]{MYexamz} % %\setcoursename{MATH 101} %\setexamname{Test 1} %\settermname{Spring 2023} %\setinstructions{% % Read each problem carefully. Show all work. %}% % %\begin{document} %\begin{versions} % \printcover % \setquestionpath{Problems/} %\begin{questions} % \questionfrombank{Solve_Linear_Equation} % \questionfrombank{State_Capitals} %\end{questions} % \printworkspace %\end{versions} %\end{document} %\end{verbatim} % % To write a new exam Test 2 in the same course, simply change the argument of % \cs{setexamname} from \texttt{Test 1} to \texttt{Test 2} and use the % appropriate question banks. With random counters and well-developed question % banks, writing exams for the next term may be as simple as changing the % term name. % %\StopEventually{^^A % \PrintChanges % \PrintIndex %} % %\section{Implementation}\label{imp} % % The \textsf{examz} document class requires the packages \textsf{environ}, \textsf{xpatch}, and \textsf{counterz}, the last of which also loads the % packages \textsf{etoolbox} and \textsf{makecmds}. % % \begin{macrocode} \RequirePackage{environ} \RequirePackage{xpatch} \RequirePackage{counterz} % \end{macrocode} % % This class inherits all of the options available to the \textsf{exam} class, % including \textsf{answers}, \textsf{noanswers}, \textsf{cancelspace}, % \textsf{nocancelspace}, and \textsf{addpoints}. The class also admits % several additional options, the first of which is called \textsf{complete}. % This option takes effect only when using the \textsf{versions} environment % (see Section \ref{imp:versions}) and will otherwise be ignored. With this % option selected, the document alternately prints each exam version with and % without its solutions. The default value of the associated boolean variable % is FALSE. Loading the option \textsf{complete} will change this value to TRUE. % This option is intended to take the place of the options \textsf{answers} and % \textsf{noanswers} and will override these two options if engaged. % % \begin{macrocode} \newbool{@examz@complete} \boolfalse{@examz@complete} \DeclareOption{complete}{\booltrue{@examz@complete}} % \end{macrocode} % % Additional options are based on features of the \textsf{counterz} package. The % option \textsf{randomize} will cause the command \cs{randprovidecounter} (and % its derivative commands) to generate new random values whereas the option % \textsf{norandomize} will cause these commands to input their values from a % file. Because this file may not exist before a first typesetting, the default % option is \textsf{randomize}. % % \begin{macrocode} \randomizectr \DeclareOption{randomize}{\randomizectr} \DeclareOption{norandomize}{\norandomizectr} % \end{macrocode} % % % Finally, the class may be loaded with an option called \textsf{prompt}. % Because the manual change of the option \textsf{randomize} may be forgotten, % resulting in the loss of counter values, the option \textsf{prompt} offers a % terminal-based dialogue through which randomization can be decided. This % action, which is executed at the beginning of the document (see below) is % based on the command \cs{promptranomizectr} from the \textsf{counterz} % package. % % \begin{macrocode} \newbool{@examz@prompt} \boolfalse{@examz@prompt} \DeclareOption{prompt}{\booltrue{@examz@prompt}} \newcommand{\promptrandomexam}{% \promptrandomizectr[\EnterResponse]{% ^^J Enter 1 to randomize document. ^^J Enter 2 to update without new randomization. }{% 1% }% }% % \end{macrocode} % % We now load the \textsf{exam} document class with all of these options. % % \begin{macrocode} \DeclareOption*{% \PassOptionsToClass{\CurrentOption}{exam} }% \ProcessOptions\relax \LoadClass{exam} % \end{macrocode} % % Next, we patch the \textsf{coverpages} environment. If the document is loaded % with the option \textsf{twoside} (passed from the \textsf{article} class) and % the \textsf{coverpages} environment produces an odd number of pages, then an % extra blank page is inserted so that the odd arabic page numerals appear on % the right page (i.e. front of the page). % % \begin{macrocode} \xpatchcmd{\endcoverpages}{\setcounter{num@coverpages}{\value{page}}}{% \ifbool{@twoside}{% \ifnumodd{\value{page}}{% % Do Nothing }{% \newpage \null \newpage }% }{% % Do nothing }% \setcounter{num@coverpages}{\value{page}}% }{}{}% % \end{macrocode} % If the class is loaded with the option \textsf{prompt} then we execute the % command \cs{promptrandomexam}. If the user elects to not randomize the % document, either by terminal input via \cs{promptrandomexam} or by instead % loading the \textsf{norandomize} option, then we execute the command % \cs{inputcountersfile}. (Note that this will produce an error if no counters % file exists, so this option should not be used for a first typesetting.) If % the user does elect to randomize the document, by terminal input or by loading % the class with the option \textsf{randomize} or by loading the class with none % of the options \textsf{randomize}, \textsf{norandomize}, or \textsf{prompt}, % then we execute the command \cs{opencountersfile}. % % \begin{macrocode} \AtBeginDocument{% \ifbool{@examz@prompt}{% \promptrandomexam }{% }% \ifrandomizectr{% \opencountersfile }{% \inputcountersfile }% }% % \end{macrocode} % %\subsection{Randomized Exams}\label{imp:versions} % % The counter \textit{numversions} determines how many versions of the exam will % be generated. The default value of \textit{numversions} is 1. % % \begin{macrocode} \newcounter{numversions} \setcounter{numversions}{1} % \end{macrocode} % %\begin{macro}{\promptversions} % % The following command is used by the \textsf{versions} environment (described % below) whenever the class is loaded with the \textsf{prompt} option. Note that % the counter is saved to the counters file. (See the documentation for the % \textsf{counterz} package.) % % \begin{macrocode} \newcommand{\promptversions}{% \typein[\NumberOfVersions]{% ^^J How many versions? }% \setcounter{numversions}{\NumberOfVersions} \savecounter{numversions} }% % \end{macrocode} % %\end{macro} % % The counter \textit{version} keeps track of the exam version when printing. % The value of \textit{version} is initialized as 1. % % \begin{macrocode} \newcounter{version} \setcounter{version}{1} % \end{macrocode} % % We now patch the parent class \textsf{exam} so that corresponding questions in % different versions will not be assigned the same question label. To accomplish % this, we append to the question labels the value of \textit{version}. We also % append an \textit{S} if the boolean \textit{answers} (from the \textsf{exam} % class) is TRUE, to distinguish between versions with and without solutions % when the class is loaded with the option \textsf{complete}. % % \begin{macrocode} \xpatchcmd{\find@latestques} {@\arabic{question}} {@\arabic{version}\ifbool{printanswers}{S}{}@\arabic{question}} {}{} \xpatchcmd{\decr@latest@ques} {question@} {question@\arabic{version}\ifbool{printanswers}{S}{}@} {}{} \xpatchcmd{\chk@incompi} {question@} {question@\arabic{version}\ifbool{printanswers}{S}{}@} {}{} \xpatchcmd{\questions} {@\arabic{question}} {@\arabic{version}\ifbool{printanswers}{S}{}@\arabic{question}} {}{} \xpatchcmd{\parts} {@\arabic{question}} {@\arabic{version}\ifbool{printanswers}{S}{}@\arabic{question}} {}{} \xpatchcmd{\subparts} {@\arabic{question}} {@\arabic{version}\ifbool{printanswers}{S}{}@\arabic{question}} {}{} \xpatchcmd{\subsubparts} {@\arabic{question}} {@\arabic{version}\ifbool{printanswers}{S}{}@\arabic{question}} {}{} \xpatchcmd{\setup@point@toks} {@\arabic{question}} {@\arabic{version}\ifbool{printanswers}{S}{}@\arabic{question}} {}{} \xpatchcmd{\refto@index} {question@} {question@\arabic{version}\ifbool{printanswers}{S}{}@} {}{} % \end{macrocode} % %\begin{macro}{\@examz@versions} % % The \textsf{versions} environment is defined via command \cs{@examz@versions}. % The single argument of this command represents the user-provided exam content, % including the \textsf{questions} environment and any pages before or after. If % the class is loaded with the option \textsf{prompt} and the exam is randomized % then the command first executes \cs{promptversions} to attain and save the % value of the counter \textit{numversions}. The main action of the command is % to use a while loop to generate versions of the exam, updating the version % and page numbers along the way. When the class is loaded with the option % \textsf{complete}, the document alternately prints without and with solutions, % updating the version only after both printings. When the class is loaded with % the option \textsf{twoside}, an extra blank page is inserted at the end of % each version when necessary to ensure that the next version starts on a front % page. % % \begin{macrocode} \newcommand{\@examz@versions}[1]{% \ifrandomizectr{% \ifbool{@examz@prompt}{% \promptversions }{% % Do Nothing }% }{% % Do Nothing }% \ifbool{@examz@complete}{% \noprintanswers }{% % Do Nothing }% \whileboolexpr{% test{\ifnumless{\value{version}}{1+\value{numversions}}} }{% \ifbool{@twoside}{% \ifnumodd{\value{page}}{% % Do Nothing }{% \newpage \null \thispagestyle{empty} \newpage }% }{% % Do Nothing }% \setcounter{page}{1} \setcounter{numquestions}{0} \setcounter{numparts}{0} \setcounter{numsubparts}{0} \setcounter{numsubsubparts}{0} \setcounter{numpoints}{0} \setcounter{numbonuspoints}{0} #1 \newpage \notbool{@examz@complete}{% \addtocounter{version}{1} }{% \notbool{printanswers}{% \printanswers }{% \noprintanswers \addtocounter{version}{1} }% }% }% }% % \end{macrocode} % %\end{macro} % %\begin{environment}{versions} % % The \textsf{versions} environment is now defined using the previous command % and the command \cs{Collect@Body}. The environment has an optional argument % with which the user may specify the number of versions. If the exam is not % randomized then the argument is ignored under the assumption that the needed % value has been inputted from the counters file after a previous randomization. % (If there is never any randomization, then there is no need for different % versions, and the environment will execute with the default number of versions % being one.) If the class is loaded with the option \textsf{prompt}, then this % optional argument will be overridden by the number provided by the user via % terminal prompt. % % \begin{macrocode} \newenvironment{versions}[1][1]{% \ifrandomizectr{% \setcounter{numversions}{#1} \savecounter{numversions} }{% % Do Nothing }% \Collect@Body\@examz@versions }{% % Empty }% % \end{macrocode} % %\end{environment} % % The \textsf{exam} document class exam prints in the console and log file some % data that includes the number of questions, total points, etc. Here we add to % that data the number of versions of the exam and whether the solutions were % printed. % % \begin{macrocode} \AtEndDocument{% \typeout{% This document contains \thenumversions\space version\ifnumequal{\value{numversions}}{1}{}{s} of the exam \ifbool{@examz@complete}{% with and without solutions. }{% \ifbool{printanswers}{% with solutions. }{% without solutions. }% }% }% }% % \end{macrocode} % %\subsection{Question Banks}\label{imp:banks} % %\begin{macro}{\@examz@questionpath} %\begin{macro}{\setquestionpath} % The default value of \cs{@examz@questionpath} is empty, but authors may use % the command \cs{setquestionpath}\marg{pathname} to change this. % % \begin{macrocode} \newcommand{\@examz@questionpath}{} \newcommand{\setquestionpath}[1]{% \renewcommand{\@examz@questionpath}{#1} }% % \end{macrocode} % %\end{macro} %\end{macro} % %\begin{macro}{\questionfrombank} % The command \cs{questionfrombank}\oarg{points}\marg{filename} uses the % command \cs{question} from the \textsf{exam} class. The first (optional) % argument is the point value of the question, and the second argument is the % name of the question bank file (without the .tex extension). The input uses % \cs{\@examz@questionpath}. In order to avoid a conflict between question banks % that use the same counter names, \cs{counterprefix} is temporarily set to % include both the name of the file and the number of the version. (See the % \textsf{counterz} package for more information about \cs{setcounterprefix}.) % % \begin{macrocode} \newcommand{\questionfrombank}[2][]{% \question[#1] \setcounterprefix{#2_Version_\arabic{version}_} \input{\@examz@questionpath #2} \clearcounterprefix }% % \end{macrocode} % %\end{macro} % %\begin{macro}{\setnumberofquestions} % % The counter \textit{@examz@qbsize} is an internal counter to represent the % number of questions in a question bank. The command % \cs{setnumberofquestions}\marg{number} is used to set this value. % % \begin{macrocode} \newcounter{@examz@qbsize} \newcommand{\setnumberofquestions}[1]{% \setcounter{@examz@qbsize}{#1} }% % \end{macrocode} % %\end{macro} % %\begin{environment}{questionbank} % % The \textsf{questionbank} environment begins by creating a random counter that % is used to determine which question will be selected and ends with the command % \cs{endinput} so that nothing after the environment appears in the question. % \begin{macrocode} \newenvironment{questionbank}{% \xrandprovidecounter{Random_Question}{1}{\value{@examz@qbsize}} }{% \endinput } % \end{macrocode} % %\end{environment} % %\begin{environment}{qbitem} % % The environment \textsf{qbitem} is a wrapper for each option in a % \textsf{questionbank} environment. The argument is an integer value that is % compared to the random counter value generated by \textsf{questionbank}. The % body of the environment is the content of the question. Additional counters % that are created and manipulated within \textsf{qbitem} should be handled by % the commands provided in the \textsf{counterz} package in order to use the % counter prefix that is created by the command \cs{questionfrombank}. % % \begin{macrocode} \NewEnviron{qbitem}[1]{% \ifnumequal{\xvalue{Random_Question}}{#1}{% \BODY }{% } } % \end{macrocode} % %\end{environment} % %\begin{macro}{\setsolutionspace} % % The command \cs{@examz@solutionspace} represents the amount of space allotted % to solutions, per the various solutions environments that are defined by the % \textsf{exam} document class. \cs{setsolutionspace}\marg{length} is used to % set this value. % % \begin{macrocode} \newcommand{\@examz@solutionspace}{1cm} \newcommand{\setsolutionspace}[1]{% \renewcommand{\@examz@solutionspace}{#1} }% % \end{macrocode} % %\end{macro} % % \noindent % For each of the six solutions environments provided by the \textsf{exam} class % there is an analogous solutions environment that automatically loads the value % of \cs{SolutionSpace} for the argument. % %\begin{environment}{qbsolution} % % \textsf{qbsolution} is equivalent to % \textsf{solution}[\cs{@examz@solutionspace}]. % % \begin{macrocode} \NewEnviron{qbsolution}{% \begin{solution}[\@examz@solutionspace] \BODY \end{solution} }% % \end{macrocode} % %\end{environment} % %\begin{environment}{qbsolutionbox} % % \textsf{qbsolutionbox} is equivalent to % \textsf{solutionbox}\{\cs{@examz@solutionspace}\}. % % \begin{macrocode} \NewEnviron{qbsolutionbox}{% \begin{solutionbox}{\@examz@solutionspace} \BODY \end{solutionbox} }% % \end{macrocode} % %\end{environment} % %\begin{environment}{qbsolutionorbox} % % \textsf{qbsolutionorbox} is equivalent to % \textsf{solutionorbox}[\cs{@examz@solutionspace}]. % % \begin{macrocode} \NewEnviron{qbsolutionorbox}{% \begin{solutionorbox}[\@examz@solutionspace] \BODY \end{solutionorbox} }% % \end{macrocode} % %\end{environment} % %\begin{environment}{qbsolutionorlines} % % \textsf{qbsolutionorlines} is equivalent to % \textsf{solutionorlines}[\cs{@examz@solutionspace}]. % % \begin{macrocode} \NewEnviron{qbsolutionorlines}{% \begin{solutionorlines}[\@examz@solutionspace] \BODY \end{solutionorlines} }% % \end{macrocode} % %\end{environment} % %\begin{environment}{qbsolutionordottedlines} % % \textsf{qbsolutionordottedlines} is equal to % \textsf{solutionordottedlines}[\cs{@examz@solutionspace}]. % % \begin{macrocode} \NewEnviron{qbsolutionordottedlines}{% \begin{solutionordottedlines}[\@examz@solutionspace] \BODY \end{solutionordottedlines} }% % \end{macrocode} % %\end{environment} % %\begin{environment}{qbsolutionorgrid} % % \textsf{qbsolutionorgrid} is equivalent to % \textsf{solutionorgrid}[\cs{@examz@solutionspace}]. % % \begin{macrocode} \NewEnviron{qbsolutionorgrid}{% \begin{solutionorgrid}[\@examz@solutionspace] \BODY \end{solutionorgrid} }% % \end{macrocode} % %\end{environment} % %\subsection{Customization Macros} % %\begin{macro}{\instructorname} %\begin{macro}{\coursename} %\begin{macro}{\examname} %\begin{macro}{\termname} %\begin{macro}{\namespace} %\begin{macro}{\instructions} %\begin{macro}{\covernoanswers} %\begin{macro}{\coveranswers} %\begin{macro}{\workspace} % % The following commands define macros, with default values, for use in % formatting headers, footers, and special pages. \cs{covernoanswers} and % \cs{workspace} are empty by default, and \cs{coveranswers} is equal to % \cs{covernoanswers} by default. % % \begin{macrocode} \newcommand{\instructorname}{Instructor Name} \newcommand{\coursename}{Course Name} \newcommand{\examname}{Exam Name} \newcommand{\termname}{Term Name} \newcommand{\namespace}{Name:~\makebox[5cm]{\hrulefill}} \newcommand{\instructions}{Instructions Here} \newcommand{\covernoanswers}{} \newcommand{\coveranswers}{\covernoanswers} \newcommand{\workspace}{} % \end{macrocode} % %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{\setinstructorname} %\begin{macro}{\setcoursename} %\begin{macro}{\setexamname} %\begin{macro}{\settermname} %\begin{macro}{\setnamespace} %\begin{macro}{\setinstructions} %\begin{macro}{\setcoveranswers} %\begin{macro}{\setcovernoanswers} %\begin{macro}{\setworkspace} % % The following commands allow a user to redefine the above macros. % \begin{macrocode} \newcommand{\setinstructorname}[1]{\renewcommand{\instructorname}{#1}} \newcommand{\setcoursename}[1]{\renewcommand{\coursename}{#1}} \newcommand{\setexamname}[1]{\renewcommand{\examname}{#1}} \newcommand{\settermname}[1]{\renewcommand{\termname}{#1}} \newcommand{\setnamespace}[1]{\renewcommand{\namespace}{#1}} \newcommand{\setinstructions}[1]{\renewcommand{\instructions}{#1}} \newcommand{\setcovernoanswers}[1]{\renewcommand{\covernoanswers}{#1}} \newcommand{\setcoveranswers}[1]{\renewcommand{\coveranswers}{#1}} \newcommand{\setworkspace}[1]{\renewcommand{\workspace}{#1}} % \end{macrocode} % %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{\printcover} % % The command \cs{printcover} executes either \cs{coveranswers} or % \cs{covernoanswers}, depending on the value of the boolean % \textsf{printanswers}. % % \begin{macrocode} \newcommand{\printcover}{% \ifbool{printanswers}{\coveranswers}{\covernoanswers} }% % \end{macrocode} % %\end{macro} % %\begin{macro}{\printworkspace} % % The command \cs{printcover} executes \cs{workspace} when the boolean % \textsf{printanswers} is false and otherwise does nothing. % % \begin{macrocode} \newcommand{\printworkspace}{% \ifbool{printanswers}{}{\workspace} }% % \end{macrocode} % %\end{macro} % % \Finale \endinput