0

I am writing a document which contains questions and answers. For example

\question{What is 2+3?}{2+3=5}
\question{What is cheese?}{Food made from milk.}

The answers are saved up to be gathered in a later section, with the twist that the answers are shuffled to prevent peeking. This means the questions must contain forward-references to the answer numbers. For example:

Q2.1 What is 2+3? (See answer 104)

Q2.2 What is cheese? (See answer 57)

I have this almost working.

The \question command writes all the answers to a temporary file, and a later \printtheanswers command sends this to an external program which

a. shuffles the answers,

b. generates Latex for the answers section, and

c. generates an auxiliary file qa.aux which defines \answernumber1, \answernumber2 etc to hold the forward-references.

This is a two-pass compilation. The qa.aux file is loaded at the beginning, if it exists. The \question command must define \answernumberN for each of them which does not exist, to expand to a placeholder.

At the moment, \question is partially-defined -- it always defines \answernumberN to a placeholder:

\newcommand{\question}[2]{
    \stepcounter{questionnumber}
    \stepcounter{questionnumberinchapter}

    % Define the placeholder for \answernumberN
    \expandafter\edef\expandafter\answernumber\roman{questionnumber}{PLACEHOLDER:\arabic{questionnumber}}

    % FOR DEBUGGING
    DEFINING \texttt{\textbackslash answernumber\roman{questionnumber} as \{PLACEHOLDER:\arabic{questionnumber}\}}

    % Write "x.y #2" to \qainpfilename
    \immediate\write\qafile{\arabic{chapter}.\arabic{questionnumberinchapter} \unexpanded{#2}}

    % Print the qustion to the document.
    Q\arabic{chapter}.\arabic{questionnumberinchapter} #1 \emph{(See answer \expandafter\answernumber\roman{questionnumber}.)}
}

Here is the line of interest:

\expandafter\edef\expandafter\answernumber\roman{questionnumber}{PLACEHOLDER:\arabic{questionnumber}}

The problem is this ALWAYS defines \answernumberN, regardless of whether it is defined in the auxiliary file.

Here is a MWE, although you can't actually compile it without the external program.

\documentclass[a4paper,10pt,openany]{scrbook}

\usepackage{verbatim}

% Define \bashline command
% Taken from https://gist.github.com/w495/7328b76e76aee49657e0bd7a3b46c870
\makeatletter
    \newcommand{\bashline@file@name}[1]{%
        /tmp/${USER}-${HOSTNAME}-\jobname-#1.tex%
    }
    \newread\bashline@file
    \newcommand{\bashline@command@one}[2][tmp]{%
        \immediate\write18{#2 > \bashline@file@name{#1}}
        \openin\bashline@file=\bashline@file@name{#1}
        % The group localizes the change to \endlinechar
        \bgroup
            \endlinechar=-1
            \read\bashline@file to \localline
            % Since everything in the group is local, 
            % we have to explicitly make the assignment global
            \global\let\bashline@result\localline
        \egroup
        \closein\bashline@file
        % Clean up after ourselves
        \immediate\write18{rm \bashline@file@name{#1}}
        \bashline@result
    }
    \newcommand{\bashline@command@many}[2][tmp]{%
        \immediate\write18{#2 > \bashline@file@name{#1}}
        \openin\bashline@file=\bashline@file@name{#1}
        % The group localizes the change to \endlinechar
        \newcount\linecnt
        \bgroup
            \endlinechar=-1
            \loop\unless\ifeof\bashline@file 
                \read\bashline@file to \localline%
                \localline
                \newline
            \repeat
        \egroup
        \closein\bashline@file
        % Clean up after ourselves
        \immediate\write18{rm \bashline@file@name{#1}}
    }
    \newcommand{\bashline}[2][tmp]{%
        \bashline@command@one[#1]{#2}%
    }
    \newcommand{\bashlines}[2][tmp]{%
        \bashline@command@many[#1]{#2}%
    }
\makeatother

% Question-answer stuff.

\def\qainpfilename{qa.inp}
\def\qaauxfilename{qa.aux}
\def\qatexfilename{qa.tex}

\newwrite\qafile
\immediate\openout\qafile=\qainpfilename

\newcounter{questionnumber}
\newcounter{questionnumberinchapter}[chapter]

\newcommand{\question}[2]{
    \stepcounter{questionnumber}
    \stepcounter{questionnumberinchapter}

    % Define the placeholder for \answernumberN
    \expandafter\edef\expandafter\answernumber\roman{questionnumber}{PLACEHOLDER:\arabic{questionnumber}}

    DEFINING \texttt{\textbackslash answernumber\roman{questionnumber} as \{PLACEHOLDER:\arabic{questionnumber}\}}

    % Write "x.y #2" to \qainpfilename
    \immediate\write\qafile{\arabic{chapter}.\arabic{questionnumberinchapter} \unexpanded{#2}}

    % Print the qustion to the document.
    Q\arabic{chapter}.\arabic{questionnumberinchapter} #1 \emph{(See answer \expandafter\answernumber\roman{questionnumber}.)}
}

\newcommand{\printtheanswers}{
    \immediate\closeout\qafile
    \bashline{bash bin/generate-answers.sh '\qainpfilename' '\qatexfilename' '\qaauxfilename'}

    \input{\qatexfilename}
}

% Demonstrate that this will not be expanded until after qa.tex has been
% generated loaded into the document.
\def\examplething{this is expanded later}



\begin{document}

TEST

\IfFileExists{\qaauxfilename}{\input{\qaauxfilename}}{AUX DOES NOT EXIST}



\chapter{Maths}

\question{What is $1+2$?}{$1+2=3$ \examplething}

\question{What is $2\times 3$?}{$2\times 3=6$}



\chapter{Science}

\question{Name the six quarks.}{Up down, charm, strange, truth, and beauty.}

\question{How many planets orbit the Sun?}{Eight. Deal with it.}



\chapter{Answers}

\printtheanswers

\end{document}

The qa.aux file which is generated for this document is

\def\answernumberi{3}% (Q1.1): $1+2=3$ \examplething 
\def\answernumberii{1}% (Q1.2): $2\times 3=6$
\def\answernumberiii{4}% (Q2.1): Up down, charm, strange, truth, and beauty.
\def\answernumberiv{2}% (Q2.2): Eight. Deal with it.

I know you can use \providecommand and various if-then constructions, but I haven't been able to get them to work when the command name is constructed with \expandafter\answernumber\roman{questionnumber}. How do I conditionally define a command whose name is built from a number like this?

  • 1
    \expandafter\edef\expandafter\answernumber\roman{questionnumber}{PLACEHOLDER:\arabic{questionnumber}} always defines \answernumber not \answernumberiii etc. – David Carlisle Apr 14 '17 at 16:57
  • 2
    can't really tell as the example isn't usable but are you looking for \expandafter\edef\csname answernumber\roman{questionnumber}\endcsname{PLACEHOLDER:\ar‌​abic{questionnumber}‌​} ? – David Carlisle Apr 14 '17 at 16:59
  • Why do you have See answer \expandafter\answernumber\roman{questionnumber}? Why aren't you using \label{} and \ref{} for cross-references like this? – cfr Apr 15 '17 at 2:18
  • @cfr Probably because I don't know how. I only use \label for chapter/section numbers. How would it be adapted for counting the nth \item in an enumeration? – spraff Apr 15 '17 at 18:19
  • 1
    Just put it after \item e.g. \item\label{enum:trigqn} or whatever. Then \ref{enum:trigqn} will give you the item's number (or letter or whatever you're using to label them). – cfr Apr 16 '17 at 1:11
0

With thanks to cfr, I now use \label and \ref

The \question command now includes

Q\arabic{chapter}.\arabic{questionnumberinchapter} #1 \emph{(See answer \expandafter\ref{\expandafter qanswer\arabic{questionnumber}}.)}

and the \printtheanswers command generates tex like this:

\item\label{qanswer123} (text of answer to the 123rd question)

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.