如何随机化章节中各节(或节中的小节)的顺序?我会按 A、B、C、... 的顺序输入它们,但在呈现的文档中,它们应该显示为 1=F、2=Y、3=C 等。因此,它们显示为从 1 开始的编号,但这不是我在源文件中编写它们的顺序。交叉引用应使用“新”编号 1,而不是原始编号。
理由:我正在写一本“游戏书”,这是一个读者可以通过阅读某些章节来决定接下来会发生什么的故事。例如,第 7 节可能会写到“你正处在岔路口。要左转,请阅读第 29 节;要右转,请阅读第 4 节。”。为了避免玩家判断哪种解决方案更好,顺序是完全随机的。
到目前为止,我使用的是手动半随机方法,并将每个新部分添加到我认为应该添加的位置。但要避免选择太近(或更糟:彼此相邻)是很棘手的,尤其是在写作过程中重新排列它们时。此外,这很麻烦,因为我无法以有助于写作的方式对各个部分进行排序(例如按章节/场景进行分组)。我们这里讨论的是 300 多个部分。
我想避免LuaLaTex
并使用XeLaTeX
。
附加问题:理想情况下,这种随机化会有一个种子,因此只要部分数量不变,它就会保持不变,或者我明确改变种子。
答案1
更新-- 现在使用每章的节数来为随机数生成器提供正确的范围。每章中不会使用两次随机数。
用法是\section{Section title}[section content]
,每次使用新章节时都会清除列表,并显示,如果放在最后的可选参数中,则\displaysections
链接和标签有效。\label
对小节的概括也是类似的。
关于随机数唯一性的补充:
\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}
}
}
循环\int_do_while:nn
运行,直到显示所有部分。如果当前随机数尚未在列表中,则将其存储在列表中 - 这样,只会添加唯一数字。这是通过
\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}}
}
现在代码:
\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}
答案2
该解决方案创建一个文件名列表,然后以随机顺序读取它们。
\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}
其中文件 sectionA 是
\section{This is section A}
\lipsum[1]
文件 sectionB 是
\section{This is section B}
\lipsum[2]
等等。
请注意,每次运行时顺序都会发生变化。
答案3
我花了几天时间研究这个,在偶然发现了游戏书包。最初,它不太适合我的目的——它正确地生成了章节引用,但不支持对章节进行改组。快速搜索后,我发现了 latex随机列表包,但这似乎更适合于逐项列表。
经过一番努力,我成功编写了宏来实现游戏书部分的随机化。我希望默认样式略有不同,以匹配我用于小说的格式(使用回忆录类),因此在开始文档之前,我在最后一次 \checkandfixthelayout 调用之后编写了一个完美运行的代码块。以下代码
%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
使用游戏书包的示例项目,您可以按以下方式包装您想要随机化的部分:
\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)
}
请注意,当使用章节引用时,您可能需要重建文件来修复它们。