4

I am doing a follow up on How to expand a macro to use it inside a question in AMC?, as suggested by @Steven B. Segletes, so the question can be answered.

Context

I'm trying to use AMC to produce an exam with code in it. However, the use of verbatim code inside the questions is beyond the scope of the package. They suggest to declare boxes and used them inside each question.

Problem

But, I found problematic to create a \newbox per question and insert it by hand. However, this is partially solved by two solutions:

  • One suggests to use named boxes using the same string as the question (which helps retrieving them automatically in the \insertbox command. However, it is hard to maintain as it needs a modification of several places when changing the ID of the question. Also, it doesn't allow me to have several boxes on the same questions (not sure if that is important now, but it may be good idea to have a more robust solution).

  • Another one uses an auto increment in the boxes numbering, which is nice. However, when the questions are shuffled the number in the question is not the same as the order in which the boxes where declared (thus not retrieving the same box).

What I will like is to have the best of both worlds: an easy way to maintain the questions and preferably an automatic (transparent) way of naming then to the user, but that the questions remained coupled with their respective boxes when shuffled.

For example, the image below shows how the codes are shown in order as they were declared, but when the questions are shuffled, they may not appear in the same order.

enter image description here

\documentclass{article}

\usepackage[box]{automultiplechoice}
\usepackage{listings}

% a simple wrapper to create boxes automatically
\makeatletter
\newcounter{myboxcounter}
\newenvironment{mybox}{%
  \stepcounter{myboxcounter}%
  \expandafter\newsavebox\csname foobox\roman{myboxcounter}\endcsname
  \global\expandafter\setbox\csname foobox\roman{myboxcounter}\endcsname\hbox\bgroup\color@setgroup\ignorespaces
}{%
  \color@endgroup\egroup
}
\newcommand{\insertbox}{\stepcounter{myboxcounter}%
  \edef\name{foobox\roman{myboxcounter}}\edef\x{%
  \expandafter\usebox\csname\name\endcsname}\x}
\makeatother


\begin{document}

%%% preparation of the groups
\begin{mybox}
\begin{lstlisting}[language=C++]
  int a = 10;
  a = a + 10;
\end{lstlisting}
\end{mybox}
\element{code}{
  \begin{question}{code 1}
    Which is the result of \texttt{a}? (question of \texttt{a+10})

    \insertbox
    \begin{choices}
      \correctchoice{10}
      \wrongchoice{20}
      \wrongchoice{0}
      \wrongchoice{30}
    \end{choices}
  \end{question}
}

\begin{mybox}
\begin{lstlisting}[language=C++]
  int a = 10;
  a = a++;
\end{lstlisting}
\end{mybox}
\element{code}{
  \begin{question}{code 2}
    Which is the result of \texttt{a}? (question of \texttt{a++})

    \insertbox
    \begin{choices}
      \correctchoice{10}
      \wrongchoice{11}
      \wrongchoice{12}
      \wrongchoice{0}
    \end{choices}
  \end{question}
}

%%% copies
\AMCrandomseed{123456789}
\onecopy{1}{
\cleargroup{all}
\setcounter{myboxcounter}{0}

\copygroup{code}{all}
\shufflegroup{all}
\insertgroup{all}
}

\end{document}
1
+100

Maybe you can use the internal AMC question identifier as a box identifier. You have to guess this identifier if you call mybox before building the question, and force AMC to set the identifier right after the mybox environment use (so a simple \element won't work).

\documentclass{article}

\usepackage[box]{automultiplechoice}
\usepackage{listings}

\begin{document}

% a simple wrapper to create boxes automatically

\makeatletter
\newcommand{\insertbox}{%
  \edef\name{foobox\romannumeral\AMCid@quest}%
  \expandafter\usebox\csname\name\endcsname%
}

\newcount\AMC@nextid
\newenvironment{mybox}{%
  % what is the next used AMC internal question identifier?
  \AMC@nextid=\AMC@numerotation\advance\AMC@nextid\@ne\relax%
  % put it in \AMC@nextid@x
  \edef\AMC@nextid@x{\romannumeral\AMC@nextid}%
  % define the savebox
  \expandafter\newsavebox\csname foobox\AMC@nextid@x\endcsname%
  % and fill it with requested content
  \global\expandafter\setbox\csname foobox\AMC@nextid@x\endcsname\hbox\bgroup\color@setgroup\ignorespaces%
}{%
  \color@endgroup\egroup%
}

\newcommand{\codequestion}[3]{% group-id question-id question-content
  % force AMC to affect the internal question identifier right now, to question #2
  \AMC@prepare{#2}%
  \element{#1}{
    \begin{question}{#2}#3\end{question}
  }
}
\newcommand{\codequestionmult}[3]{%
  \AMC@prepare{#2}%
  \element{#1}{
    \begin{questionmult}{#2}#3\end{questionmult}
  }
}

\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{mybox}
  \begin{lstlisting}[language=C++]
    int a = 10;
    a = a + 10;
  \end{lstlisting}
\end{mybox}
\codequestion{code}{code 1}{
  Which is the result of \texttt{a}? (question of \texttt{a+10})

  \insertbox
  \begin{choices}
    \correctchoice{10}
    \wrongchoice{20}
    \wrongchoice{0}
    \wrongchoice{30}
  \end{choices}
}

\begin{mybox}
  \begin{lstlisting}[language=C++]
    int a = 10;
    a = a++;
  \end{lstlisting}
\end{mybox}
\codequestion{code}{code 2}{
  Which is the result of \texttt{a}? (question of \texttt{a++})

  \insertbox
  \begin{choices}
    \correctchoice{10}
    \wrongchoice{11}
    \wrongchoice{12}
    \wrongchoice{0}
  \end{choices}
}

%%% copies
\AMCrandomseed{123456789}
\onecopy{5}{
  \begin{center}
    \Large\bf Exam
  \end{center}


  \cleargroup{all}

  \copygroup{code}{all}
  \shufflegroup{all}
  \insertgroup{all}
}

\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.