LaTeX code for multiple-choice exam

The creation of multiple-choice exam with answer key can be pretty complex when you want multiple sets of the same exam with shuffle questions and choices. This gets increasingly more complex as you want more sets.

Let solve one problem at a time. Generating 2n sets of multiple choice is pretty easy. For example, if you want 8 sets, then you can just divide the question sets into 3 parts, with 2 versions for each part. Combined, you get 8 sets. Easy (?).

Now for the LaTeX code to help with the other part. To be fair, this code still requires you to shuffle things manually. But it 1) auto-number the question and choice so you can just re-arrange them without changing the number and 2) automatically generate answer key based on choice marked as correct.

The Code

First, we need some packages. These should be available on any standard LaTeX installation.

\usepackage{xspace}
\usepackage{listofitems}
\usepackage{tabto}

Then, we define some macro to control how to display the answer key:

\newcommand{\showAns}{1}
\newcommand{\showInlineAns}{1}

The first setting shows the answer key at the end of the question set (useful for distributing the key after the exam, or to give to TA to do the grading), and the second shows the key directly under each question (useful for checking the key correctness).

Now to the meat of the entire operation. This is going to be quite complex:

 1\def\ansL{}
 2\newcounter{question}
 3\newcounter{choice}[question]
 4\newcommand{\lquestion}[1][1]{\textbf{Q\the\numexpr\value{question}-#1\relax}\xspace}
 5\newcommand{\nquestion}[1][1]{\textbf{Q\the\numexpr\value{question}+#1\relax}\xspace}
 6\def\qref #1{\textbf{Q\ref{#1}}}
 7\newenvironment{question}[1]%
 8{%
 9	\filbreak\refstepcounter{question}\textbf{Q\thequestion.} #1 
10	
11}%
12{%
13        \ifx\correctAns\undefined%
14            \edef\correctAns{NONE}%
15        \fi%
16        \global\edef\ansL{\ansL,\correctAns}%
17	\ifnum\showInlineAns=1
18	
19	\vspace{-0.5cm}
20	\emph{Answer.} \correctAns
21	\fi
22}%
23\newcommand{\C}[0]{\stepcounter{choice}\textbf{\thechoice) }}
24\newcommand{\CA}[0]{\stepcounter{choice}\textbf{\thechoice) }\edef\correctAns{\thechoice}}
25\newcommand{\setAns}[1]{\edef\correctAns{#1}}
26\newcommand{\answerList}[1][5]{\setsepchar{,} \ignoreemptyitems \readlist\ans{\ansL}\NumTabs{#1} \foreachitem\item\in\ans{Q\itemcnt{}: \item \tab }}

To break up this chunk of code:

Line 1 defines the macro ansL, which will store our answer key in a comma-seperated format.

Line 2-3 define the question and choice counter, with the choice counter reset everytime the question counter steps.

Line 4-5 define the \lquestion[n] and \nquestion[n] to reference to the previous or next question. The [n] parameter is optional and will just be n previous or next question. For example, in the text of Q38, if we write \lquestion[2] it will show up as Q36.

Line 6 defines the macro \qref{label} to display the referenced question number in the Qxx format.

Line 7-22 define the main question environment. The header part steps the counter and display the question text. The footer check if \correctAns exists, if it it isn’t define the \correctAns as NONE. It then append the current \correctAns to the global \ansL to store them, and also display the \correctAns if \showInlineAns is defined.

Line 23-24 define the \C and \CA macro for choice. Beside stepping the choice counter, the \CA will also define \correctAns to the current choice number.

Line 25 is a \setAns macro for explicitly set the answer key directly. For example, for bonus question with no real correct answer. You can do \setAns{n/a}.

Line 26 is the \answerList macro for displaying all the answer keys. It uses the listofitems package to read the comma-seperated answer in \ansL and display them with spacing provide by tabto package.

Usage

For each question, use the following templates. \CA indicate the correct choice. You can also use \label{q:xx} the same way you would reference other questions, with \qref to display the reference. You can also use \lquestion and \nquestion as we define above.

\begin{question}{From \lquestion what we should do?}
    \C 1  \\
    \C 2  \\
    \C 4  \\
    \CA 3 \\
\end{question}

Finally, at the end of the question set, the following code will output the answer key in a seperated page if required.

\ifnum\showAns=1
    \newpage
    \textbf{Answer.}
    
    \answerList[5]
\fi