6

How would you randomize the order of sections in a chapter (or subsection in a section)? I would type them in the order A, B, C, ..., but in the rendered document they should appear as 1=F, 2=Y, 3=C, etc. Thus they appear numbered starting with 1, but that is not the order I write them in the source file. Crossreferences should use the "new" numbering 1 to whatever and never the original one.

Rationale: I am writing a "game book", that is a story where the reader can decide what is going on by reading certain sections. E.g. section 7 might read "You are at a fork of the road. To go left read section 29, to go right read section 4.". To avoid judgement by the player which solution would be better, the order is totally random.

So far I used a manual semi-random approach and added each new section where I felt it should go. But it is tricky to avoid that choices are too close together (or worse: next to each other), especially if they get rearranged during writing. Also this is cumbersome as I can't order the sections in a way it helps my while writing (e.g. cluster by chapter/scene). And we are talking 300+ sections here.

I would like to avoid LuaLaTex and use XeLaTeX.

Bonus question: Ideally there would be a seed to this randomization, so it stays the same as long as the amount of sections does not change, or I explicitly change the seed.

5
  • 2
    I think, this is possible if the relevant sections are in several files and those being input with a random scheme that uses the same rand seed, otherwise the ordering (and labeling) would be different in each run
    – user31729
    Commented Feb 26, 2016 at 15:58
  • I've thought of putting the sections in a file, and use shell scripts to split+rearrange them, but that feels like a workaround and is not so platform independet. So I still hope this can be done somehow within LaTeX. Individual files would be too much of a hassle to work on.
    – TeXter
    Commented Feb 26, 2016 at 16:00
  • Well, you know, that \section{A}...\section{B} fixes the order of the text in which they appear
    – user31729
    Commented Feb 26, 2016 at 16:02
  • Why don't you just hyperlink the whole thing? You can divide the whole thing into many files, or use one file with all the optional details in doubly linked appendixes. See elfsoft2000.com/acoustic/enclosure.pdf Commented Feb 26, 2016 at 17:07
  • This will be a printed book.
    – TeXter
    Commented Feb 26, 2016 at 17:09

3 Answers 3

6

Update -- The number of sections per chapter is used now to provide the correct range for the random generator. No random number is used twice within a chapter.

The usage is \section{Section title}[section content], the list is cleared each time a new chapter is used and displayed with \displaysections, linking and labelling works, if the \label is placed within the final optional argument.

The generalization to subsections is similar.

Addition about the uniqueness of the random number:

\NewDocumentCommand{\displaysections}{}{%
  \f@rst=\@ne % Direct manipulation works ;-)
  \l@st=\seq_count:N \chapterwise_seq%
  \int_zero:N \l_tmpa_int
  \seq_clear:N \l_tmpa_seq
  \int_do_while:nn { \l_tmpa_int < \seq_count:N \chapterwise_seq} {
    \rand%
    \seq_if_in:NxF \l_tmpa_seq {\number\value{myrandcounter}} { %
      \int_incr:N \l_tmpa_int 
      \seq_put_right:Nx \l_tmpa_seq {\number\value{myrandcounter}}
    }
  }
  \seq_map_inline:Nn \l_tmpa_seq {%
    \seq_item:Nn \chapterwise_seq {##1}
  }
}

The \int_do_while:nn loops runs until all sections are displayed. The current random number is stored into a list if it is not already in the list -- this way, only unique numbers are added. This is done with

\seq_if_in:NxF \l_tmpa_seq {\number\value{myrandcounter}} { %
  \int_incr:N \l_tmpa_int 
  \seq_put_right:Nx \l_tmpa_seq {\number\value{myrandcounter}}
}

Now the code:

\documentclass{book}

\usepackage[seed=100,counter=myrandcounter,first=1,last=100]{lcg}
\usepackage{xpatch}
\usepackage{xparse}
\usepackage{blindtext} % Just for dummy text
\usepackage{hyperref}
\usepackage{cleveref}


\makeatletter
\ExplSyntaxOn
\seq_new:N \chapterwise_seq  
\let\latex@@section\section
\RenewDocumentCommand{\section}{som+O{}}{%
 \IfBooleanTF{#1}{%
   \latex@@section*{#3}%
 }{%
   \IfValueTF{#2}{%
     \seq_put_right:Nn \chapterwise_seq {\latex@@section[#2]{#3} #4}
   }{%
     \seq_put_right:Nn \chapterwise_seq {\latex@@section{#3} #4}
   }
 }
}

\xpretocmd{\chapter}{\seq_clear:N \chapterwise_seq}{}{}

\newcommand{\getnumofsections}{%
  \seq_count:N \chapterwise_seq%
}


\newcounter{tempcntr}

\NewDocumentCommand{\displaysections}{}{%
  \f@rst=\@ne % Direct manipulation works ;-)
  \l@st=\seq_count:N \chapterwise_seq%
  \int_zero:N \l_tmpa_int
  \seq_clear:N \l_tmpa_seq
  \int_do_while:nn { \l_tmpa_int < \seq_count:N \chapterwise_seq} {
    \rand%
    \seq_if_in:NxF \l_tmpa_seq {\number\value{myrandcounter}} { %
      \int_incr:N \l_tmpa_int 
      \seq_put_right:Nx \l_tmpa_seq {\number\value{myrandcounter}}
    }
  }
  \seq_map_inline:Nn \l_tmpa_seq {%
    \seq_item:Nn \chapterwise_seq {##1}
  }
}

\ExplSyntaxOff

\makeatother


\begin{document}
\chapter{First}

\section{A}[This is section A \label{Sec:A}] 

\section{B}[This is section B -- in \ref{Sec:A}]

\section{C}[This is section C]

\typeout{Foo}
\displaysections

\typeout{Foo}

\chapter{Second}

    \section{A}[This is another section A \label{Sec:AA}] 

\section{B}[This is another section B -- in \ref{Sec:AA}]

\section{C}[This is another section C  \label{Sec:CC} \subsection{Foo} \blindtext[50]]

\section{D}[This is another section D \label{Sec:DD}] 

\section{E}[This is another section E -- in \nameref{Sec:A} we see]

\section{F}[This is another section F  \label{Sec:FF} \subsection{Another Foo} \blindtext[10]]

\displaysections
\end{document}

enter image description here

enter image description here

2
  • This looks very good and even supports multiple chapters with independent random subsections. Since my TeX-fu is not good enough: can you briefly explain how this solution guarantees no duplicates are picked within a chapter? I guess I have to manually select a first/last for lcg that is large enough that it fits all sections?
    – TeXter
    Commented Mar 1, 2016 at 16:15
  • @TeXter: Regarding the first and the last random number; You may set them in the beginning, large enough, but I think my code does not need them at all, as it determines the range before it uses \displaysection. Regarding the uniqueness of the random number, I will add an explanation to the post
    – user31729
    Commented Mar 1, 2016 at 16:22
3

This solution creates a list of filenames then reads them in random order.

\documentclass{report}
\usepackage{pgfmath}
\usepackage{lipsum}

\newcounter{index}[chapter]

\newcommand{\addfilename}[1]% #1=filename
{\stepcounter{index}%
 \expandafter\xdef\csname section\theindex\endcsname{#1}}

\newcommand{\randomize}%
{\bgroup% use local definitions (\total, \temp)
  \edef\total{\theindex}%
  \setcounter{index}{0}%
  \loop\stepcounter{index}% last loop does nothing
    \edef\temp{\csname section\theindex\endcsname}%
    \pgfmathparse{int((\total-\theindex)*rnd+\theindex)}%
    \expandafter\xdef\csname section\theindex\endcsname{\csname section\pgfmathresult\endcsname}%
    \expandafter\xdef\csname section\pgfmathresult\endcsname{\temp}%
  \ifnum\value{index}<\total\relax \repeat
%
  \setcounter{index}{0}%
  \loop\stepcounter{index}%
    \input{\csname section\theindex\endcsname}
  \ifnum\value{index}<\total\relax \repeat
\egroup}

\begin{document}

\chapter{First}
\addfilename{sectionA}
\addfilename{sectionB}
\addfilename{sectionC}
\addfilename{sectionD}
\randomize

\chapter{Second}
\addfilename{sectionA}
\addfilename{sectionB}
\addfilename{sectionC}
\addfilename{sectionD}
\randomize

\end{document}

where file sectionA is

\section{This is section A}
\lipsum[1]

file sectionB is

\section{This is section B}
\lipsum[2]

and so on.

Note that the order changes each time you run it.

2
  • This solution seems to do something different. It keeps the order of sections of the original document, but just gives it random section numbers. That is not what I intended. I would need in your screenshot that it reads: First -> 1.A normally 1.3, 1.B normally 1.1 1.C normally 1.5 etc. (the actual section numers are not important, they will be hidden anyway, but the random order of the content is)
    – TeXter
    Commented Mar 1, 2016 at 16:04
  • Could you put the source for each section into a different file? Then all one has to do is read the files in a random order. Commented Mar 1, 2016 at 16:32
1

I've spent a couple of days looking at this, after coming across the gamebook package. Initially, it didn't quite suit my purposes - it generates section references correctly, but doesn't support shuffling the sections. A quick search revealed mentions of the latex randomlist package, but this seemed geared towards itemized lists.

After a bit of work, I successfully wrote macros to implement randomizing of the gamebook sections. I wanted the default styling to be slightly different, to match the format I use for my novels (using the memoir class), so I wrote a block of code that worked perfectly after the final \checkandfixthelayout call before beginning the document. The following code

%Gamebook specific inclusion
\usepackage{gamebook} % [debug,draft]

% In case I want to override the turn to option
\renewcommand{\gbturntext}{turn~to~}

% Turn off chapter and section labels (sections would appear as 0.x instead of x in the memoir class)
\counterwithout{section}{chapter}

%redefine the titleformat section if necesary (this is the default, which has a box around the section number)
\titleformat{\section}[block]{%
\centering\bfseries}{\fbox{\thesection}}{1em}{\relax}

    %redefine the fancyfacing header to use the gamebook styling (this is in the gamebook sample, but I'm overriding in the style of my novel headers)
\fancypagestyle{fancyfacing}{
    \renewcommand{\sectionmark}[1]{\markboth{\thesection}{\thesection}}%
    \fancyhead{} %clear head
    \fancyfoot{} % clear foot
    %Print PDF (comment these 3 lines out for digital)
    % in gamebooks, instead of page we want the marks
    \fancyhead[RO,LE]{\small\ifthenelse{\equal{\firstleftmark}%
{\leftmark}}{\leftmark}{\firstleftmark~--~\leftmark}}%
    \fancyhead[CO]{\itshape My book title}% Title of my book on odd pages
    \fancyhead[CE]{\itshape Author Name}% Author name on even pages

    \renewcommand{\headrulewidth}{0pt} %hide header rule (no line below)
}   

%randomising sections
% Seed is optional, but without it the layout is different each time
\usepackage[seed=101]{randomlist}

\makeatletter

%Define a new command, RandomOrdering, using the example in randomlist package for latex usage
\def\RandomOrdering{
    \ClearList{*RandomList*}%
    \@ifnextchar\bgroup{\@randomorder}{\@@randomorder}%
}

\long\def\@randomorder#1{%
    \InsertRandomItem{*RandomList*}{#1}%Insert argument into random position in the list
    \@ifnextchar\bgroup{\@randomorder}{\@@randomorder}%
}

\def\@@randomorder{%
    \long\edef\RL@body{}%
    %loop the items in the (now random) list
    \RLfor \RL@var = 0 to \RL@lenof{*RandomList*}-1 \do{%
        \long\edef\RL@body{%Instead of inserting the itemised list code as in the example, I am simply injecting the content from between the parameter brackets
            \unexpanded\expandafter{\RL@body}%
            \unexpanded\expandafter{%
                \csname *RandomList*-\RL@var\endcsname% Print out the content of the list item before expanding RL@body
            }%
        }%
    }%
    \RL@body
}
\makeatother
%end randomising sections

%end gamebook inclusion

Using the gamebook package's sample project, you can wrap the sections you want randomised in the following way:

\gbsection{start}
    First section, printed in order.
    ...

\gbsection{wrongsec}
    Second section, also in order

\RandomOrdering{ % from here on, anything in the open and close brackets gets shuffled.

    \gbsection{redbutton}
    Section in random order (1)

}{  

    \gbsection{steelopen}
    Section in random order (2)

}{

    \gbsection{steelclosed}
    Section in random order (3)

}

Beware, when using section references, you may need to rebuild the file to fix them.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .