diff options
author | Karl Berry <karl@freefriends.org> | 2023-06-08 19:50:11 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2023-06-08 19:50:11 +0000 |
commit | c4a353064f802d0c980714ce1578e24a40834cbb (patch) | |
tree | 211a7adf1cefd87a1d2c461c7513f0a0b2fa82ff /Master/texmf-dist/source/latex/examz/examz.dtx | |
parent | 92cec824af2c643ec0cb870e5243eee8923ae13e (diff) |
examz (8jun23)
git-svn-id: svn://tug.org/texlive/trunk@67303 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/examz/examz.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/examz/examz.dtx | 1168 |
1 files changed, 1168 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/examz/examz.dtx b/Master/texmf-dist/source/latex/examz/examz.dtx new file mode 100644 index 00000000000..fe0eae0ddd5 --- /dev/null +++ b/Master/texmf-dist/source/latex/examz/examz.dtx @@ -0,0 +1,1168 @@ +% \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} +%</driver> +%<class>\NeedsTeXFormat{LaTeX2e} +%<class>\ProvidesClass{examz} +%<*class> + [2023/06/07 v1.0.0 Randomized exams with multiple versions] +%</class> +% +%<*driver> +\documentclass{ltxdoc} +\usepackage[numbered]{hypdoc} +\EnableCrossrefs +\CodelineIndex +\RecordChanges +\begin{document} + \DocInput{examz.dtx} +\end{document} +%</driver> +% \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}[<optional number>] +% <exam content here> +%\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
\ No newline at end of file |