Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I need to create an environment (let's call it randomizer) that randomly changes the order of its lines, which may contain any text or latex commands (assume without verifying that they don't break across lines).

For example, I have several tex files, each containing one problem and I want to generate a set of problems put in a random order. Then I would use

\begin{randomizer}
  \input{problem1}
  \input{problem2}
  \input{problem3}
  \input{problem4}
\end{randomizer}

I want also to be able to control the random process, by having the possibility to specify a seed number for the generator.

share|improve this question
2  
You could take a look to examdesign: multiple versions of the same test can be generated automatically, with the ordering of questions within each section randomly permuted so as to minimize cheating; –  knut Jan 11 '12 at 22:04
    
I already have the problems written in their specific format and using examdesign would mean to rewrite them. –  digital-Ink Jan 11 '12 at 22:24
2  
It's not only to use examdesign, but also to look, how they solved it there - perhaps you could use the same logic. –  knut Jan 11 '12 at 23:06
add comment

2 Answers

up vote 4 down vote accepted

Here is the solution based on the RANOMIZE-IN-PLACE procedure in the CLRS. The procedure is defined as

n = A.length
for i=1 to n
   swap A[i] with A[random(i,n)]

(CLRS does not like end for, so we do not use it either).

TeX code uses random.tex by Donald Arseneau (should be in your distribution). This code puts in 10 macros \csname num0\endcsname, \csname num1\endcsname, ... some random permutation of numbers 0..9 (I used macros instead of counters to save the latter). You can use this code to write something like \expandafter\input{file\csname num0\endcsname}, \expandafter\input{file\csname num1\endcsname} etc.

\documentclass{article}
\input{random}
\begin{document}
\newcount\number
\newcount\randomnum

% Put 0..9 into \num0..\num9
\number=0
\loop\ifnum\the\number<10\relax
\expandafter\edef\csname num\the\number\endcsname{\the\number}
\advance\number by 1
\repeat

% Randomize
\number=0
\loop\ifnum\the\number<10\relax
\setrannum{\randomnum}{\the\number}{9}  % Random number between \number and 9
\edef\tmpnum{\csname num\the\number\endcsname}
\expandafter\edef\csname num\the\number\endcsname{\csname
  num\the\randomnum\endcsname} 
\expandafter\edef\csname num\the\randomnum\endcsname{\tmpnum}
\advance\number by 1
\repeat

% Print the results:
\number=0
\loop\ifnum\the\number<10\relax
Macro \textbackslash num\the\number\space contains \expandafter\csname
num\the\number\endcsname
\advance\number by 1\relax\par
\repeat
% To input in random order files file0.tex, file1.tex, file2.tex,... 
% use instead
% \number=0
% \loop\ifnum\the\number<10\relax
% \expandafter\input{file\csname num\the\number\endcsname}
% \advance\number by 1\relax
% \repeat

\end{document}

See random.tex documentation about seeding the generator.

Output example:

Macro \num0 contains 7
Macro \num1 contains 1
Macro \num2 contains 9
Macro \num3 contains 3
Macro \num4 contains 6
Macro \num5 contains 8
Macro \num6 contains 2
Macro \num7 contains 5
Macro \num8 contains 4
Macro \num9 contains 0
share|improve this answer
    
How can this be applied when instead of sequential filenames I have some arbitrary filenames? –  digital-Ink Jan 13 '12 at 15:05
    
You can put the filenames in an "array": \def\Input#1{\ifcase#1\input{first}\or\input{second}\or...\fi}. Thus the command \Input{0} inputs first.tex, etc. Then your last loop should call \expandafter\Input{\csname num\the\number\endcsname} –  Boris Jan 13 '12 at 16:16
add comment

If you have luatex, you can also use lua. This uses the same shuffling method as Boris's answer, but in lua. Call lualatex with the following file:

\documentclass{article}
\usepackage{luacode}

\newcommand\SeedRnd[1][os.time()]{\directlua{rndseed = #1; math.randomseed(rndseed)}}
\newcommand\RndSeed{\directlua{tex.print(rndseed)}}

\SeedRnd %Takes an optional parameter if you want a specific random seed

\newcommand\RndOrderInput[1]{%
\luaexec{
local table = {#1}
function shuffle(t)
  local n = \#t
  while n > 1 do
    local k = math.random(n)
    t[n], t[k] = t[k], t[n]
    n = n - 1
  end
  return t
end
for k,v in pairs(shuffle(table)) do tex.print("\string\\input{" .. v .. "}") end
}}

\begin{document}
Random seed: \RndSeed %so you will be able to recreate this order. 
\RndOrderLoad{'file1', 'file2', 'file3', 'file4'}
\end{document}

Note that the file names have to be written as lua strings, that is 'file1' or "file1", not just file1.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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