12

I need some help with a crazy idea. For a book I want the page numbers to be a random permutation. As an example, if the book would have 5 pages, I want something like (4,1,2,5,3). Optimally, the table of contents and references would work. I don't know enough about TeX to do it myself. I am already happy about some directions in how to proceed.

I use the book LaTeX class and XeLatex.

Thank you!

13
  • 7
    @Karlo Perhaps there is in automated friendliness deletion algorithm in place ;)
    – Eman Resu
    May 11, 2017 at 13:08
  • 1
    @EmanResu See meta.stackexchange.com/a/93989 . May 11, 2017 at 17:54
  • 2
    @RobtA The goal is to confuse people ;)
    – Eman Resu
    May 11, 2017 at 20:36
  • 1
    Gosh, if the goal is to confuse people, then all you have do do is let them read the TeX source document.
    – user103221
    May 11, 2017 at 21:21
  • 1
    @RobtA There are multiple ways to confuse people. And some are funnier than others.
    – Eman Resu
    May 11, 2017 at 21:25

3 Answers 3

12

This uses the specified permutation within range, if you have more pages than that it reverts to normal, so you can always modify the definition at the end once you know how many pages you have

enter image description here

\documentclass{book}

\renewcommand\thepage{%
\ifcase\value{page}%
0\or
4\or
1\or
2\or
5\or
6\or
3\else
\arabic{page}%
\fi}

\begin{document}

\tableofcontents

\chapter{Intro}
\section{Zzzz}aaaa
\section{Zzzzz}aaaa \clearpage bbbb
\section{Zzzzz}aaaa


\chapter{Something}
\section{Zzzz zzz}aaaa
\section{Zzzzzz zzz}aaaa \clearpage bbbb
\section{Zzzzzzz zzz}aaaa


\end{document}
3
  • 3
    No fancy expl3 solution? I'm really disappointed.
    – TeXnician
    May 11, 2017 at 13:05
  • 3
    @TeXnician I need to leave an opening for egreg to try to steal a tick. May 11, 2017 at 13:07
  • that should work. i have like 170 pages, so will generate the beginning with python and paste it in the tex code.
    – Eman Resu
    May 11, 2017 at 13:11
7

Just for fun an implementation that doesn't require external programs and just needs two LaTeX runs. However, the pages will change at every subsequent run.

\documentclass{article}
\usepackage{xparse}
\usepackage{zref-user,zref-abspage,atveryend}
\usepackage{kantlipsum}

% Coerce zref into not adding the last page number in the .aux file
% which would always issue the warning that labels have changed
\makeatletter
\zref@newlist{lastabs}
\zref@addprop{lastabs}{abspage}
\AfterLastShipout{%
  \if@filesw
    \begingroup
      \advance\c@page\m@ne
      \toks@\expandafter{\Z@L@lastabs}%
      \expandafter\zref@wrapper@immediate\expandafter{%
        \expandafter\ZREF@label\expandafter{\the\toks@}{LastAbsPage}%
      }%
    \endgroup
  \fi
}
\makeatother

\ExplSyntaxOn

\cs_set_eq:Nc \zref_extract:nn { zref@extract }

% a variant of the Knuth shuffle algorithm as implemented
% in https://tex.stackexchange.com/a/224559/4427

\cs_new:Nn \knuthshuffle_get_random:Nnn
 {
  \int_set:Nn #1 { \fp_eval:n { randint(#2,#3) } }
 }

\tl_new:N \l_knuthshuffle_tempa_tl
\tl_new:N \l_knuthshuffle_tempb_tl
\int_new:N \l_knuthshuffle_random_int
\prop_new:N \l_knuthshuffle_newperm_prop
\prop_new:N \g_knuthshuffle_identity_prop % the identity
\seq_new:N \g_knuthshuffle_permutation_seq

\cs_new_protected:Nn \knuthshuffle_generate:n
 {
  \prop_set_eq:NN \l_knuthshuffle_newperm_prop \g_knuthshuffle_identity_prop
  \int_step_inline:nnnn { #1 } { -1 } { 2 }
   {
    \knuthshuffle_get_random:Nnn \l_knuthshuffle_random_int { 1 } { ##1 }
    \prop_get:NnN \l_knuthshuffle_newperm_prop { ##1 } \l_knuthshuffle_tempa_tl 
    \prop_get:NVN \l_knuthshuffle_newperm_prop \l_knuthshuffle_random_int \l_knuthshuffle_tempb_tl 
    \prop_put:NnV \l_knuthshuffle_newperm_prop { ##1 } \l_knuthshuffle_tempb_tl
    \prop_put:NVV \l_knuthshuffle_newperm_prop \l_knuthshuffle_random_int \l_knuthshuffle_tempa_tl
   }
  \seq_clear:N \g_knuthshuffle_permutation_seq
  \int_step_inline:nnnn { 1 } { 1 } { #1 }
   {
    \seq_gput_right:Nx \g_knuthshuffle_permutation_seq
     {
      \prop_item:Nn \l_knuthshuffle_newperm_prop { ##1 }
     }
   }
  %\seq_show:N \g_knuthshuffle_permutation_seq % for debugging
 }
\cs_generate_variant:Nn \knuthshuffle_generate:n { x }

\AtBeginDocument
 {
  \int_compare:nT { \zref_extract:nn {LastAbsPage}{abspage} > 0 }
   {
    \int_step_inline:nnnn { 1 } { 1 } { \zref_extract:nn {LastAbsPage}{abspage} }
     {
      \prop_gput:Nnn \g_knuthshuffle_identity_prop { #1 } { #1 }
     }
    \knuthshuffle_generate:n { \zref_extract:nn {LastAbsPage}{abspage} }
    \renewcommand{\thepage}{\randomarabic{page}}
   }
 }

\NewExpandableDocumentCommand{\randomarabic}{m}
 {
  \seq_item:Nn \g_knuthshuffle_permutation_seq { \value{#1} }
 }

\ExplSyntaxOff

\begin{document}

\kant[1-102]

\ExplSyntaxOn
% for showing the used page numbers
\seq_use:Nn \g_knuthshuffle_permutation_seq { ,~ }
\ExplSyntaxOff

\end{document}

At the end the sequence of the used page numbers has been added by way of example.

Here's the bottom of the last page.

enter image description here

A more complex strategy can cope also with the table of contents. Now the random sequence is only computed if the number of pages has changed since the last LaTeX run, otherwise the previous sequence is used.

\documentclass{article}
\usepackage{xparse}
\usepackage{zref-abspage,atveryend}
\usepackage{kantlipsum}

\makeatletter
\zref@newlist{lastabs}
\zref@addprop{lastabs}{abspage}
\AfterLastShipout{%
  \if@filesw
    \begingroup
      \advance\c@page\m@ne
      \toks@\expandafter{\Z@L@lastabs}%
      \expandafter\zref@wrapper@immediate\expandafter{%
        \expandafter\ZREF@label\expandafter{\the\toks@}{LastAbsPage}%
      }%
    \endgroup
  \fi
}
\makeatother

\ExplSyntaxOn

\cs_set_eq:Nc \zref_extract:nn { zref@extract }

\cs_new:Nn \knuthshuffle_get_random:Nnn
 {
  \int_set:Nn #1 { \fp_eval:n { randint(#2,#3) } }
 }

\tl_new:N \l_knuthshuffle_tempa_tl
\tl_new:N \l_knuthshuffle_tempb_tl
\int_new:N \l_knuthshuffle_random_int
\prop_new:N \l_knuthshuffle_newperm_prop
\prop_new:N \g_knuthshuffle_identity_prop % the identity
\seq_new:N \g_knuthshuffle_permutation_seq

\cs_new_protected:Nn \knuthshuffle_generate:n
 {
  \prop_set_eq:NN \l_knuthshuffle_newperm_prop \g_knuthshuffle_identity_prop
  \int_step_inline:nnnn { #1 } { -1 } { 2 }
   {
    \knuthshuffle_get_random:Nnn \l_knuthshuffle_random_int { 1 } { ##1 }
    \prop_get:NnN \l_knuthshuffle_newperm_prop { ##1 } \l_knuthshuffle_tempa_tl 
    \prop_get:NVN \l_knuthshuffle_newperm_prop \l_knuthshuffle_random_int \l_knuthshuffle_tempb_tl 
    \prop_put:NnV \l_knuthshuffle_newperm_prop { ##1 } \l_knuthshuffle_tempb_tl
    \prop_put:NVV \l_knuthshuffle_newperm_prop \l_knuthshuffle_random_int \l_knuthshuffle_tempa_tl
   }
  \seq_clear:N \g_knuthshuffle_permutation_seq
  \int_step_inline:nnnn { 1 } { 1 } { #1 }
   {
    \seq_gput_right:Nx \g_knuthshuffle_permutation_seq
     {
      \prop_item:Nn \l_knuthshuffle_newperm_prop { ##1 }
     }
   }
  %\seq_show:N \g_knuthshuffle_permutation_seq % for debugging
 }
\cs_generate_variant:Nn \knuthshuffle_generate:n { x }

\AtBeginDocument
 {
  \seq_if_empty:NT \g_knuthshuffle_permutation_seq
   {
    \int_compare:nT { \zref_extract:nn {LastAbsPage}{abspage} > 0 }
     {
      \int_step_inline:nnnn { 1 } { 1 } { \zref_extract:nn {LastAbsPage}{abspage} }
       {
        \prop_gput:Nnn \g_knuthshuffle_identity_prop { #1 } { #1 }
       }
      \knuthshuffle_generate:n { \zref_extract:nn {LastAbsPage}{abspage} }
     }
   }
  \renewcommand{\thepage}{\randomarabic{page}}
 }

\AfterLastShipout
 {
  \int_compare:nT { \value{abspage} = \zref_extract:nn {LastAbsPage}{abspage} }
   {
    \iow_now:cx { @auxout }
     {
      \randompagesequence
       { \zref_extract:nn {LastAbsPage}{abspage} }
       { \seq_use:Nn \g_knuthshuffle_permutation_seq { , } }
     }
   }
 }

\cs_new_protected:Npn \randompagesequence #1 #2
 {
  \int_compare:nT { #1 = \zref_extract:nn {LastAbsPage}{abspage} }
   {
    \seq_gset_from_clist:Nn \g_knuthshuffle_permutation_seq { #2 }
   }
 }
\NewExpandableDocumentCommand{\randomarabic}{m}
 {
  \seq_item:Nn \g_knuthshuffle_permutation_seq { \value{#1} }
 }

\ExplSyntaxOff

\begin{document}

\ExplSyntaxOn
\seq_show:N \g_knuthshuffle_permutation_seq
\ExplSyntaxOff

\tableofcontents

\section{One}
\kant[1-20]
\section{Two}
\kant[21-30]
\section{Three}
\kant[31-53]

\ExplSyntaxOn
% for showing the used page numbers
\seq_use:Nn \g_knuthshuffle_permutation_seq { ,~ }
\ExplSyntaxOff

\end{document}

enter image description here

1
5

Well, just to play around with it: A solution with expl3 with the only drawback that it will not check for an existing page with that number. The max page number can be set in \l__blob_int.

random

\documentclass{book}

\usepackage{expl3}
\ExplSyntaxOn
\clist_new:N \l__quack_clist
\int_new:N \l__blub_int
\int_gset:Nn \l__blub_int {0}
\int_new:N \l__blob_int
\int_gset:Nn \l__blob_int {10}
\int_do_while:nn {\l__blub_int < \l__blob_int}
    {
        \clist_put_right:NV \l__quack_clist \l__blub_int
        \int_incr:N \l__blub_int
    }
\renewcommand\thepage{%
    \clist_item:Nn \l__quack_clist {\fp_eval:n {randint(\clist_count:N\l__quack_clist)}}
}
\ExplSyntaxOff

\begin{document}

\tableofcontents

\chapter{Intro}
\section{Zzzz}aaaa
\section{Zzzzz}aaaa \clearpage bbbb
\section{Zzzzz}aaaa


\chapter{Something}
\section{Zzzz zzz}aaaa
\section{Zzzzzz zzz}aaaa \clearpage bbbb
\section{Zzzzzzz zzz}aaaa


\end{document}

You must log in to answer this question.

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