6

This is a follow-up question to this question:
Generate exam from a question bank?

In the following code by @Werner, I am curious to know why do I need to wait about 30 seconds or more to generate a new set of questions? What happens during these seconds? Why LaTeX needs this time?

\documentclass{article}
\usepackage{multicol}% Just for this example
\usepackage{filecontents}
\begin{filecontents*}{bankA.tex}
\begin{questionblock}
Question 1
\end{questionblock}
\begin{questionblock}
Question 2
\end{questionblock}
\begin{questionblock}
Question 3
\end{questionblock}
\begin{questionblock}
Question 4
\end{questionblock}
\begin{questionblock}
Question 5
\end{questionblock}
\begin{questionblock}
Question 6
\end{questionblock}
\begin{questionblock}
Question 7
\end{questionblock}
\begin{questionblock}
Question 8
\end{questionblock}
\begin{questionblock}
Question 9
\end{questionblock}
\begin{questionblock}
Question 10
\end{questionblock}
\end{filecontents*}

\usepackage{catchfile,environ,tikz}

\makeatletter% Taken from https://tex.stackexchange.com/q/109619/5764
\def\declarenumlist#1#2#3{%
  \expandafter\edef\csname pgfmath@randomlist@#1\endcsname{#3}%
  \count@\@ne
  \loop
    \expandafter\edef
    \csname pgfmath@randomlist@#1@\the\count@\endcsname
      {\the\count@}
    \ifnum\count@<#3\relax
    \advance\count@\@ne
  \repeat}
\def\prunelist#1{%
  \expandafter\xdef\csname pgfmath@randomlist@#1\endcsname
          {\the\numexpr\csname pgfmath@randomlist@#1\endcsname-1\relax}
  \count@\pgfmath@randomtemp 
  \loop
    \expandafter\global\expandafter\let
    \csname pgfmath@randomlist@#1@\the\count@\expandafter\endcsname
    \csname pgfmath@randomlist@#1@\the\numexpr\count@+1\relax\endcsname
    \ifnum\count@<\csname pgfmath@randomlist@#1\endcsname\relax
      \advance\count@\@ne
  \repeat}
\makeatother

% Define how each questionblock should be handled
\newcounter{questionblock}
\newcounter{totalquestions}
\NewEnviron{questionblock}{}%

\newcommand{\randomquestionsfrombank}[2]{%
  \CatchFileDef{\bank}{#1}{}% Read the entire bank of questions into \bank
  \setcounter{totalquestions}{0}% Reset total questions counters  ***
  \RenewEnviron{questionblock}{\stepcounter{totalquestions}}% Count every question  ***
  \bank% Process file  ***
  \declarenumlist{uniquequestionlist}{1}{\thetotalquestions}% list from 1 to totalquestions inclusive.
  \setcounter{totalquestions}{#2}% Start the count-down
  \RenewEnviron{questionblock}{%
    \stepcounter{questionblock}% Next question
    \ifnum\value{questionblock}=\randomquestion 
      \par% Start new paragraph
      \BODY% Print question
    \fi
  }%
  \foreach \uNiQueQ in {1,...,#2} {% Extract #2 random questions
    \setcounter{questionblock}{0}% Start fresh with question block counter
    \pgfmathrandomitem\randomquestion{uniquequestionlist}% Grab random question from list
    \xdef\randomquestion{\randomquestion}% Make random question available globally
    \prunelist{uniquequestionlist}% Remove picked item from list
    \bank% Process file
  }}

\begin{document}

\begin{multicols}{3}
  \foreach \x in {1,...,6} {
    \bigskip
    \randomquestionsfrombank{bankA.tex}{6}
  }
\end{multicols}

\end{document}

By the way, my own file is in Persian and I'm using xelatex if it helps.

10

Each pseudo-random number generated using PGF uses a seed that is generated by \pgfmathsetseed. The PGF manual mentions the following about this macro:

\pgfmathsetseed{<integer>}

Explicitly sets the seed for the pseudo-random number generator. By default it is set to the value of \time x \year.

Well, it's obvious that the only influence in terms of changing a pseudo-random number would stem from \time, since it's more likely to change before \year does ;)

So, what is \time? According to TeX by Topic (section 33.5 Time, p 263):

TeX has four parameters, \year, \month, \day, and \time, that tell the time when the current job started. After this, the parameters are not updated. The user can change them at any time.

All four parameters are integers; the \time parameter gives the number of minutes since midnight that the current job started.

Note that \time represents only minutes (since midnight). As such, it'll only change every minute (which falls within "every 30 seconds or more"; you may just have noticed this behaviour around a minute-mark).

To see what \time looks like, add \showthe\time to your code and check the .log.

| improve this answer | |
  • Thanks for your prompt and great answer. The only thing is that when I add showthe\time to my code, it gives me this warning: LaTeX Warning: Overwriting file ./bankA.tex'.\openout15 = bankA.tex'. – Vahid Damanafshan Dec 15 '14 at 8:10
  • @VahidDamanafshan: The warning you mention stems from the use of the filecontents package which allows overwriting of existing files (and always warns about it). \showthe\time should show up in your .log showing (say) 1419 for 11:39PM. – Werner Dec 15 '14 at 8:13
  • Wouldn't using \pdfuniformdeviate relieve the OP from the issue? – egreg Dec 15 '14 at 17:56
  • @egreg: Yes, it should. I'll mock up a solution using \pdfuniformdeviate and update my answer here (otherwise this question might become obsolete). – Werner Dec 15 '14 at 17:59

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.