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!

  • 7
    @Karlo Perhaps there is in automated friendliness deletion algorithm in place ;) – Eman Resu May 11 '17 at 13:08
  • 1
    @EmanResu See meta.stackexchange.com/a/93989 . – Emil Jeřábek May 11 '17 at 17:54
  • 2
    @RobtA The goal is to confuse people ;) – Eman Resu May 11 '17 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 '17 at 21:21
  • 1
    @RobtA There are multiple ways to confuse people. And some are funnier than others. – Eman Resu May 11 '17 at 21:25
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
    No fancy expl3 solution? I'm really disappointed. – TeXnician May 11 '17 at 13:05
  • 3
    @TeXnician I need to leave an opening for egreg to try to steal a tick. – David Carlisle May 11 '17 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 '17 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

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}

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.