randomize the order of text lines in a .tex file

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.

-
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
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

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}
\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}
\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
\repeat
% To input in random order files file0.tex, file1.tex, file2.tex,...
% \number=0
% \loop\ifnum\the\number<10\relax
% \expandafter\input{file\csname num\the\number\endcsname}
% \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

-
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

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.

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