3

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. But, I found problematic to create a \newbox per question and insert it by hand.

Thus, I searched for a solution on how to create and insert boxes automatically (following this question and this answer).

Problem

But now, I'm stuck with the expansion of the macros. As the macro I'm using inserts always the last created box. As it seems that the AMC package post processes all the elements (questions) in the \onecopy macro, and it expands my macro \insertbox then. However, I need to insert the expanded version of the macro in every element, in order to insert the expanded name of the box I created.

Thus, how can I expand the definition of the box and insert it in each question?

I tried to store the \savebox definition in another macro an insert it after, using \edef but that doesn't work either.

I will like to redefine \insertbox in such a way that is expanded with the name of the temporal box I created, instead of being expanded until the call of \onecopy.

Code

\documentclass{article}

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

% a simple wrapper to create boxes automatically
\makeatletter
\newcounter{myboxcounter}
\newenvironment{mybox}{%
  \addtocounter{myboxcounter}{1}%
  \expandafter\newsavebox\csname foobox\roman{myboxcounter}\endcsname
  \global\expandafter\setbox\csname foobox\roman{myboxcounter}\endcsname\hbox\bgroup\color@setgroup\ignorespaces
}{%
  \color@endgroup\egroup
}
% first try
% \newcommand{\insertbox}{\expandafter\usebox\csname\name\endcsname}
% second one
\newcommand{\insertbox}{\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}?

    \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}?

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

%%% copies
\onecopy{1}{
\insertgroup{code}
}

\end{document}

As you can see in the image below, both inserted codes belong to the last box created. As the macro seems to expand later, instead of when called in the \element macro. enter image description here

1

Here, I reset the counter to 0 before the final \onecopy and redefine \insertbox to step the counter with its output.

\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
}
% first try
% \newcommand{\insertbox}{\expandafter\usebox\csname\name\endcsname}
% second one
\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}?

    \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}?

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

%%% copies
\setcounter{myboxcounter}{0}
\onecopy{1}{
\insertgroup{code}
}

\end{document}

enter image description here

  • That is a nice workaround. However, if I use the functionality of AMC to shuffle the questions I will have problems, as the questions are not necessarily in the same order as they were input in the text. – adn Aug 5 '14 at 20:19
  • 1
    @adn True enough. But I don't have a (workaround)^2 yet... – Steven B. Segletes Aug 5 '14 at 20:29
  • any workaround yet? – adn Mar 30 '15 at 1:25
  • @adn I'm sorry, but I would have to know a lot more about how the shuffle operation of automultiplechoice operates, in order to even have an idea. Unfortunately, I have not tried to get to the bottom of that. Perhaps you could compose an MWE that makes use of the shuffle (showing the problem of renumbering) and ask it as a new question? – Steven B. Segletes Mar 30 '15 at 2:31
1

I'm afraid you have to name the boxes, so that they can be retrieved in the right order. You can use the question ID as a name for the boxes:

\documentclass{article}

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

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

\begin{document}

%%% preparation of the groups
\begin{mybox}{code 1}
\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}?

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

\begin{mybox}{code 2}
\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}?

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

%%% copies
\onecopy{5}{
\shufflegroup{code}
\insertgroup{code}
}

\end{document}

However, with this answer,

  • you can't use multiple boxes for one question
  • if you change the question ID, you must remember to change it at two different places in the source code

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.