# How do I put a die roll at the top of each page?

I was thinking about a trick I heard of in old RPG books and wondered how you would do it in LaTeX.

So it used to be hard to find RPG dice in stores (That is, dice with 4, 6, 8, 10, 12 and 20 sides. Note that all of these but the d10 are platonic solids), so that one book put a series of dice at the top of each page. You simply flipped the book open to a random page and read out which of the dice you wanted.

How would I set a document to automatically have a dice roll of a set number of sides at the top of each page, and ensure there is an even balance of all possible rolls? (ie so for a d20, a 40 page document has two of each number, a 25 page document has 20 rolls and 5 blank pages at the end) and that they are randomly distributed (so that you can't flip to the start of the book to add to your chances for a low roll, for example).

Code for an arbitrary number of sides would be the best, as they I could tweak it for any dice I wanted. This is mostly for fun, as every gamer I know has more dice you then you shake a stick at, but I'm curious how you would go about doing it.

Edit of Clarification: I don't want help drawing the dice: I could use an image, there is a package for it, etc. I'd make a question about that. What I want is the numbers evenly distributed to each page, and the placement of them throughout the book randomized.

Ok, I wrote a quick psudocode that might work. I have no idea if this is the best way to do it, or if it is possible in LaTeX, but it might be a start?

Pages := Number of pages
Sides := Number of sides on die
Count := Pages/Sides (rounded down)
Skip := Pages mod Sides //Might as well place the blank pages at the front
Set all pages to false
{
while(j := 0, j < Count, j++)
{
Random := Random number between 1 and Pages
if(Page{Random} = false)
{
Place i on Page{Random}
Set Page{Random} = true
}
else
{
j--
}
}


This doesn't ensure a fair distribution, but if I see a bunch of clumps of stuff I could just recompile.

• Ehh, 1. Get total number of pages (lastpage/pageslts). 2. Calculate the needed dices and their amount (any math package would probably do, something with a mod function, and can be done with plain TeX counts). 3. “Draw” the dices (TikZ, PSTricks, etc.), for d6 exist even a few packages that provides simple symbols. 4. Add the (possible randomized drawing) to every page: everypage, everyshi, … Nov 10, 2013 at 10:42
• It might be easier just to pre-generate a bunch of dice images and insert a different one on each page, or use a table lookup (see \csname). Nov 11, 2013 at 16:44

You can use the background package to put things on every page, the rest is done by TikZ:

## Code

\documentclass{scrartcl}
\usepackage[margin=25mm]{geometry}
\usepackage{background}
\usepackage{lipsum}

\usetikzlibrary{calc,shapes.geometric}

\backgroundsetup%
{   contents=%
{   \begin{tikzpicture}
[   overlay,
remember picture,
wx/.style={draw,regular polygon, minimum size=1.5cm, above,fill=red!10,thick},
w4820/.style={wx, regular polygon sides=3},
w6/.style={wx, regular polygon sides=4},
w12/.style={wx, regular polygon sides=5},
w10/.style={wx, kite,kite vertex angles=100 and 60,minimum size=1cm},
line join=round,
]
\node[w4820] at ($(current page.north west)+(4,-2)$) {\pgfmathparse{random(1,4)}\pgfmathresult};
\node[w6] at ($(current page.north west)+(6,-2)$) {\pgfmathparse{random(1,6)}\pgfmathresult};
\node[w4820] at ($(current page.north west)+(8,-2)$) {\pgfmathparse{random(1,8)}\pgfmathresult};
\node[w10] at ($(current page.north west)+(10,-2)$) {\pgfmathparse{random(1,10)}\pgfmathresult};
\node[w12] at ($(current page.north west)+(12,-2)$) {\pgfmathparse{random(1,12)}\pgfmathresult};
\node[w4820] at ($(current page.north west)+(14,-2)$) {\pgfmathparse{random(1,20)}\pgfmathresult};
\end{tikzpicture}
},
color=black,
angle=0,
scale=1,
opacity=1,
}

\begin{document}

\lipsum[1-100]

\end{document}


## Edit 1

Here's finally an automatic version. It checks the total number of pages, and then draws the dices, the values equally distributed, and does not draw any further if there's no more room for an other set.

The dices are supposed to be, from left to right, d4, d6, d8, d10,d12 and d20.

As it turns out, most d10 of people I know actually use the "inverted" kite.

To use different dice, just change the values in the for lop in \setinitialdicevalues, e.g. \foreach \x [count=\c] in {6,10,12,20,24,30} and provide fitting syles in the tikzpicture, e.g. add stlyes w24and w30

## Code

\documentclass{scrartcl}
\usepackage[margin=25mm]{geometry}
\usepackage{background}
\usepackage{lipsum}
\usepackage{xstring}
\usepackage{xifthen}
\usetikzlibrary{calc,shapes.geometric}

\usepackage{totcount}
\regtotcounter{page}

\newcommand{\setinitialdicevalues}
{   \xdef\dicedata{+}
\foreach \x [count=\c] in {4,6,8,10,12,20}
{   \pgfmathtruncatemacro{\maxsets}{(\totvalue{page}-1)/\x}
\pgfmathtruncatemacro{\maxpage}{\maxsets*\x}
\xdef\mytemplist{,}
\ifthenelse{\maxsets > 0}
{   \foreach \y in {1,...,\maxpage}
{   \pgfmathtruncatemacro{\mytempvalue}{mod(\y-1,\x)+1}
\xdef\mytemplist{\mytemplist\mytempvalue,}
}
\xdef\myrandomlist{,}
\foreach \y in {\maxpage,...,1}
{   \pgfmathtruncatemacro{\nei}{random(1,\y)}
\pgfmathtruncatemacro{\neipo}{\nei+1}
\StrBetween[\nei,\neipo]{\mytemplist}{,}{,}[\nextelement]
\StrSubstitute[1]{\mytemplist}{,\nextelement,}{,}[\mytemplisttwo]
\xdef\mytemplist{\mytemplisttwo}
\xdef\myrandomlist{\myrandomlist\nextelement,}
}
\xdef\dicedata{\dicedata\maxpage+\myrandomlist+}
}
{   \xdef\dicedata{\dicedata0++}
}
}
\typeout{\dicedata}
}

\newcommand{\getdicelist}[1]%
{ \pgfmathtruncatemacro{\lowerindex}{2*#1}%
\pgfmathtruncatemacro{\upperindex}{2*#1+1}%
\StrBetween[\lowerindex,\upperindex]{\dicedata}{+}{+}[\mytempdata]%
\xdef\currentdicelist{\mytempdata}%
}

\backgroundsetup%
{   contents=%
{   \begin{tikzpicture}
[   overlay,
remember picture,
wx/.style={draw, minimum size=1.5cm, above,fill=red,font=\bfseries\selectfont,text=white,rounded corners=0.5mm,inner sep=1pt},
w4/.style={wx, regular polygon, regular polygon sides=3},
w6/.style={wx, regular polygon, regular polygon sides=4},
w8/.style={w4},
w10/.style={wx, kite,kite vertex angles=100 and 60,minimum size=1cm,shape border rotate=180},
w12/.style={wx, regular polygon, regular polygon sides=5},
w20/.style={w4},
]
\foreach \x [count=\c] in {4,6,8,10,12,20}
{   \pgfmathtruncatemacro{\lowerindex}{2*\c-1}
\pgfmathtruncatemacro{\upperindex}{2*\c}
\StrBetween[\lowerindex,\upperindex]{\dicedata}{+}{+}[\currentlastpage]%
\pgfmathtruncatemacro{\firstemptypage}{\currentlastpage+1}
\ifthenelse{\value{page} < \firstemptypage}
{   \pgfmathtruncatemacro{\lowerindex}{2*\c}%
\pgfmathtruncatemacro{\upperindex}{2*\c+1}%
\StrBetween[\lowerindex,\upperindex]{\dicedata}{+}{+}[\currentdicelist]%
\StrBetween[1,2]{\currentdicelist}{,}{,}[\mynextnumber]
\node[w\x] at ($(current page.north west)+(2+2*\c,-2)$) {\mynextnumber};
\StrSubstitute[1]{\currentdicelist}{,\mynextnumber,}{,}[\mytempdicelist]
\StrSubstitute[1]{\dicedata}{+\currentdicelist+}{+\mytempdicelist+}[\mytempdicedata]
\xdef\dicedata{\mytempdicedata}
%\node[w\x] at ($(current page.north west)+(2+2*\c,-2)$) {\pgfmathparse{random(1,\x)}\pgfmathresult};
}
{
}
}
\end{tikzpicture}
},
color=black,
angle=0,
scale=1,
opacity=1,
}

\AtBeginDocument{\setinitialdicevalues\par\bigskip}

\begin{document}

total pages: \pgfmathparse{int(\totvalue{page}-1)}\pgfmathresult\bigskip

\lipsum[1-100]
\lipsum[1-100]
\lipsum[1-60]

\end{document}


## Output

This is page 31 of 37. So we see d4, d6, d8 and d12, but not d10 (last on page 30) or d20 (last on page 20).

• Even more Dang, you want an even distribution, not total randomness. That gonna be harder... Nov 12, 2013 at 19:25
• Is that what D&D dice look like? The kite seems unlikely. Nov 12, 2013 at 23:01
• @JohnKormylo: That's what they look like, see e.g. here. Nov 13, 2013 at 5:14
• I also discovered that there are seven dice in a set, with two octagonal trapzohedrons, one for 0-9 or 1-10 and the other for 0-90 or 10-100 (I couldn't tell which). I take it not all seven are thrown every time. So one can have a random number of dice, a random selection or dice, and random throws for each die. BTW, your kite is upside down. Nov 13, 2013 at 14:42
• Not on the dice I own ;) Nov 13, 2013 at 17:36

I replaced the original answer to combine dice and pre-generated headers. First is the main file:

\documentclass{article}
\usepackage{fancyhdr}
\usepackage{tikz}

\input{dice}% file containing shape definitions

\pagestyle{fancy}

%%%%%%%%%%%%%%%%%%%%%%%%% dice macros %%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcounter{dice}

\newcommand{\createdice}[1]% #1 = tikz path
{\stepcounter{dice}
\expandafter\def\csname dice\Roman{dice}\endcsname{
\begin{tikzpicture}
\path #1;
\end{tikzpicture}
}}

% macros for nodes, #1 = dice value

\def\fourside#1{node[fourside,draw=black]{#1}}
\def\sixside#1{node[sixside,draw=black]{#1}}
\def\eightside#1{node[eightside,draw=black]{#1}}
\def\tenside#1{node[tenside,draw=black]{#1}}
\def\twelveside#1{node[twelveside,draw=black]{#1}}
\def\twentyside#1{node[twentyside,draw=black]{#1}}

\input{random}% file containing random dice throws

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

Test dice macros:\vfil

\begin{tikzpicture}
\path (0,0) \fourside{1}
(1.5,0) \sixside{2}
(3,0) \eightside{3}
(4.5,0) \tenside{4}
(6,0) \tenside{50}
(7.5,0) \twelveside{6}
(9,0) \twentyside{7};
\end{tikzpicture}

\vspace*{0.5in}
To draw the dodecahedron, first draw a decagon by placing a vertex
on a circle with a 1 cm diameter every $36^\circ$.
Since the bottom vertex is also part of a pentagon, given the
aspect ratio of the wide half to the narrow half (1.77)
we can compute the $y$ coordinate of the top edge of this pentagon
(-0.332 cm).
Since the two vertexes on this edge are in a straight line
from the center at $-36^\circ$ and $-144^\circ$,
the radius of the interior pentagon is given by
$r = \frac{0.332 \textrm{ cm}}{\sin(36^\circ)} = 0.349 \textrm{ cm.}$

To draw the icosahedron, first draw a hexagon by placing a vertex
on a circle with a 1 cm diameter every $60^\circ$.
Except for the center triangle, every edge is foreshortened,
so we need to calculate the apparent length of one of the lines
connecting the outer hexagon to the interior triangle.

Consider a pentagonal pyramid inscribed in a 1 cm diameter circle
whose cross section is shown below
\begin{center}
\begin{tikzpicture}
\draw (0,0) coordinate(A) --node[midway,below]{0.905 cm}
(3.62,0) coordinate(B) --node[midway,above right]{0.577 cm}
(1.624,1.16) coordinate(C) --node[midway,above left]{0.499 cm}
(0,0);
\draw (.5,0) arc(0:35.3:.5);
\draw (3.12,0) arc(180:149.8:.5);
\end{tikzpicture}\\
\end{center}
where a face is to the left and an edge is to the right.
Using the law of cosines, one can calculate the two angles
($35.5^\circ$ and $30.2^\circ$).
So if the face (left) is perpendicular to the viewer, the edge (right)
will be foreshortened by $\cos(65.7^\circ)$.
Finally, if each triangle is inscribed into a circle of radius $r$,
each edge will be $2r\cos(30^\circ)$ and the total distance from the
center to the outside circle is given by
$r + 2r\cos(30^\circ)\cos(65.7^\circ) = 1.71 r = 0.5\textrm{ cm}$
and therefore $r = 0.292$ cm.

\newpage

\newpage

\end{document}


Next is the file dice.tex containing the dice definitions:

% tetrahedron

\pgfdeclareshape{fourside}{
\anchor{center}{\pgfpointorigin}    % within the node, (0,0) is the center

\anchor{text}   % this is used to center the text in the node
{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}

\foregroundpath{ % draw border
\pgfpathmoveto{\pgfpoint{0cm}{.3cm}}
\pgfpathlineto{\pgfpoint{.433cm}{-.45cm}}
\pgfpathlineto{\pgfpoint{-.433cm}{-.45cm}}
\pgfpathlineto{\pgfpoint{0cm}{.3cm}}
\pgfusepath{draw}  %draw border
\pgfusepath{draw}  %draw rectangle
}}

% cubic

\pgfdeclareshape{sixside}{
\anchor{center}{\pgfpointorigin}    % within the node, (0,0) is the center

\anchor{text}   % this is used to center the text in the node
{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}

\foregroundpath{ % draw border
\pgfpathrectanglecorners{\pgfpoint{.4cm}{.4cm}}{\pgfpoint{-.4cm}{-.4cm}}
\pgfusepath{draw}  %draw rectangle
}}

% octahedron

\pgfdeclareshape{eightside}{
\anchor{center}{\pgfpointorigin}    % within the node, (0,0) is the center

\anchor{text}   % this is used to center the text in the node
{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}

\foregroundpath{ % draw border
\pgfpathmoveto{\pgfpoint{0cm}{.5cm}}
\pgfpathlineto{\pgfpoint{.433cm}{.25cm}}
\pgfpathlineto{\pgfpoint{.433cm}{-.25cm}}
\pgfpathlineto{\pgfpoint{0cm}{-.5cm}}
\pgfpathlineto{\pgfpoint{-.433cm}{-.25cm}}
\pgfpathlineto{\pgfpoint{-.433cm}{.25cm}}
\pgfpathlineto{\pgfpoint{0cm}{.5cm}}
\pgfpathlineto{\pgfpoint{.433cm}{-.25cm}}
\pgfpathlineto{\pgfpoint{-.433cm}{-.25cm}}
\pgfpathlineto{\pgfpoint{0cm}{.5cm}}
\pgfusepath{draw}  %draw interiaor
}}

% decahedron

\pgfdeclareshape{tenside}{
\anchor{center}{\pgfpointorigin}    % within the node, (0,0) is the center

\anchor{text}   % this is used to center the text in the node
{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}

\foregroundpath{ % draw border
\pgfpathmoveto{\pgfpoint{0cm}{.5cm}}
\pgfpathlineto{\pgfpoint{.294cm}{-.154cm}}
\pgfpathlineto{\pgfpoint{0cm}{-.3cm}}
\pgfpathlineto{\pgfpoint{-.294cm}{-.154cm}}
\pgfpathlineto{\pgfpoint{0cm}{.5cm}}
\pgfpathlineto{\pgfpoint{.475cm}{.1cm}}
\pgfpathlineto{\pgfpoint{.475cm}{-.1cm}}
\pgfpathlineto{\pgfpoint{0cm}{-.5cm}}
\pgfpathlineto{\pgfpoint{-.475cm}{-.1cm}}
\pgfpathlineto{\pgfpoint{-.475cm}{.1cm}}
\pgfpathlineto{\pgfpoint{0cm}{.5cm}}
\pgfpathmoveto{\pgfpoint{.294cm}{-.154cm}}
\pgfpathlineto{\pgfpoint{.475cm}{-.1cm}}
\pgfpathmoveto{\pgfpoint{-.475cm}{-.1cm}}
\pgfpathlineto{\pgfpoint{-.294cm}{-.154cm}}
\pgfpathmoveto{\pgfpoint{0cm}{-.5cm}}
\pgfpathlineto{\pgfpoint{0cm}{-.3cm}}
\pgfusepath{draw}  %draw interiaor
}}

% dodecahedron

\pgfdeclareshape{twelveside}{
\anchor{center}{\pgfpointorigin}    % within the node, (0,0) is the center

\anchor{text}   % this is used to center the text in the node
{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}

\foregroundpath{ % draw border
\pgfpathmoveto{\pgfpoint{0cm}{.5cm}}
\pgfpathlineto{\pgfpoint{0.294cm}{.405cm}}
\pgfpathlineto{\pgfpoint{.475cm}{.173cm}}
\pgfpathlineto{\pgfpoint{.475cm}{-.173cm}}
\pgfpathlineto{\pgfpoint{.294cm}{-.405cm}}
\pgfpathlineto{\pgfpoint{0cm}{-.5cm}}
\pgfpathlineto{\pgfpoint{-.294cm}{-.405cm}}
\pgfpathlineto{\pgfpoint{-.475cm}{-.173cm}}
\pgfpathlineto{\pgfpoint{-.475cm}{.173cm}}
\pgfpathlineto{\pgfpoint{-.294cm}{.405cm}}
\pgfpathlineto{\pgfpoint{0cm}{.5cm}}
\pgfpathlineto{\pgfpoint{0cm}{.349cm}}
\pgfpathlineto{\pgfpoint{.332cm}{.108cm}}
\pgfpathlineto{\pgfpoint{.205cm}{-.282cm}}
\pgfpathlineto{\pgfpoint{-.205cm}{-.282cm}}
\pgfpathlineto{\pgfpoint{-.332cm}{.108cm}}
\pgfpathlineto{\pgfpoint{0cm}{.349cm}}
\pgfpathmoveto{\pgfpoint{.475cm}{.173cm}}
\pgfpathlineto{\pgfpoint{.332cm}{.108cm}}
\pgfpathmoveto{\pgfpoint{.294cm}{-.405cm}}
\pgfpathlineto{\pgfpoint{.205cm}{-.282cm}}
\pgfpathmoveto{\pgfpoint{-.294cm}{-.405cm}}
\pgfpathlineto{\pgfpoint{-.205cm}{-.282cm}}
\pgfpathmoveto{\pgfpoint{-.475cm}{.173cm}}
\pgfpathlineto{\pgfpoint{-.332cm}{.108cm}}
\pgfusepath{draw}  %draw interiaor
}}

% icosohedron

\pgfdeclareshape{twentyside}{
anchor{center}{\pgfpointorigin} % within the node, (0,0) is the center

anchor{text}    % this is used to center the text in the node
{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}

\foregroundpath{ % draw border
\pgfpathmoveto{\pgfpoint{0cm}{.5cm}}
\pgfpathlineto{\pgfpoint{.454cm}{.262cm}}
\pgfpathlineto{\pgfpoint{.454cm}{-.262cm}}
\pgfpathlineto{\pgfpoint{0cm}{-.5cm}}
\pgfpathlineto{\pgfpoint{-.454cm}{-.262cm}}
\pgfpathlineto{\pgfpoint{-.454cm}{.262cm}}
\pgfpathlineto{\pgfpoint{0cm}{.5cm}}
\pgfpathlineto{\pgfpoint{0cm}{.292cm}}
\pgfpathlineto{\pgfpoint{.253cm}{-.146cm}}
\pgfpathlineto{\pgfpoint{-.253cm}{-.146cm}}
\pgfpathlineto{\pgfpoint{0cm}{.292cm}}
\pgfpathlineto{\pgfpoint{.454cm}{.262cm}}
\pgfpathlineto{\pgfpoint{.253cm}{-.146cm}}
\pgfpathlineto{\pgfpoint{0cm}{-.5cm}}
\pgfpathlineto{\pgfpoint{-.253cm}{-.146cm}}
\pgfpathlineto{\pgfpoint{-.454cm}{.262cm}}
\pgfpathlineto{\pgfpoint{0cm}{.292cm}}
\pgfpathmoveto{\pgfpoint{.454cm}{-.262cm}}
\pgfpathlineto{\pgfpoint{.253cm}{-.146cm}}
\pgfpathmoveto{\pgfpoint{-.454cm}{-.262cm}}
\pgfpathlineto{\pgfpoint{-.253cm}{-.146cm}}
\pgfusepath{draw}  %draw interiaor
}}


Last is the file random.tex containing the pre-generated random dice. This was generated using a C program, so I could have as easily cranked out 100 as 1. While it is possible to do calculations using LaTeX, WHY?

\createdice{\fourside{3}}
\createdice{\eightside{6}}
\createdice{\twentyside{1}}
\createdice{\twelveside{6}}
\createdice{\eightside{1}}
\createdice{\sixside{6}}
\createdice{\sixside{3}}
\createdice{\tenside{7}}
\createdice{\eightside{8}}
\createdice{\eightside{7}}
\createdice{\fourside{3}}
\createdice{\twentyside{8}}
\createdice{\eightside{3}}
\createdice{\fourside{3}}
\createdice{\fourside{1}}
\createdice{\fourside{3}}
\createdice{\tenside{0}}
\createdice{\twelveside{1}}
\createdice{\fourside{2}}
\createdice{(0,0) \tenside{20}
(1.5,0) \tenside{7}}
\createdice{\tenside{9}}
\createdice{\twelveside{2}}
\createdice{\tenside{0}}
\createdice{\twentyside{19}}
\createdice{\twelveside{10}}
\createdice{(0,0) \tenside{20}
(1.5,0) \tenside{6}}
\createdice{\fourside{4}}
\createdice{\fourside{1}}
\createdice{\twelveside{8}}
\createdice{\tenside{8}}
\createdice{(0,0) \tenside{60}
(1.5,0) \tenside{4}}
\createdice{\tenside{3}}
\createdice{\twelveside{1}}
\createdice{\eightside{8}}
\createdice{(0,0) \tenside{30}
(1.5,0) \tenside{0}}
\createdice{\fourside{3}}
\createdice{\sixside{3}}
\createdice{\eightside{5}}
\createdice{\sixside{5}}
\createdice{\twelveside{2}}
\createdice{\sixside{1}}
\createdice{\eightside{6}}
\createdice{\sixside{4}}
\createdice{\twentyside{20}}


• While it is possible to do calculations using LaTeX, WHY? Watch this until 0:45 ;-) Nov 14, 2013 at 10:49
• I seem to have exceeded some limit. Also, I noticed that the title says a random die (singular) so I changed the one time pad accordingly. Nov 15, 2013 at 22:03
• @JohnKormylo So that when I recompile the document I get difference dice rolls, and I don't need to include any external code if someone else wants to compile it. This way I'll have to redo a bunch of code every time I want to rerandomize things. Nov 19, 2013 at 3:31
• You could just roll dice if you want new random numbers, but it's your call. Nov 19, 2013 at 4:15

While my preferred style is to use C for calculations and LaTeX for typesetting, there is enough general interest in random numbers that I decided to make my own LaTeX PRNG (pseudo random number generator).

\documentclass{article}
\usepackage{fancyhdr}
\usepackage{tikz}

\input{random}% file containig PRNG
\input{dice}% file containing shape definitions

\newcount\test

\makeatletter
\newcommand{\makedice}% random dice and random throws
{\setrand{7}
\test = \c@rand
\ifnum\test=0{
\setrand{4}
\begin{tikzpicture}
\path node[fourside,draw=black]{\arabic{rand}};
\end{tikzpicture}
}
\else \ifnum\test=1{
\setrand{6}
\begin{tikzpicture}
\path node[sixside,draw=black]{\arabic{rand}};
\end{tikzpicture}
}
\else \ifnum\test=2{
\setrand{8}
\begin{tikzpicture}
\path node[eightside,draw=black]{\arabic{rand}};
\end{tikzpicture}
}
\else \ifnum\test=3{
\setrand{10}
\begin{tikzpicture}
\path node[tenside,draw=black]{\arabic{rand}};
\end{tikzpicture}
}
\else \ifnum\test=4{
\setrand{10}
\def\dice{\arabic{rand}0}
\setrand{10}
\begin{tikzpicture}
\path (0,0) node[tenside,draw=black]{\dice}
(1.5,0) node[tenside,draw=black]{\arabic{rand}};
\end{tikzpicture}
}
\else \ifnum\test=5{
\setrand{12}
\begin{tikzpicture}
\path node[twelveside,draw=black]{\arabic{rand}};
\end{tikzpicture}
}
\else {
\setrand{20}
\begin{tikzpicture}
\path node[twentyside,draw=black]{\scriptsize\arabic{rand}};
\end{tikzpicture}
} \fi \fi \fi \fi \fi \fi}
\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}
\randinit
\pagestyle{fancy}

Test dice nodes:
\vspace{0.5in}

\begin{tikzpicture}
\path (0,0) node[fourside,draw=black]{1}
(1.5,0) node[sixside,draw=black]{2}
(3,0) node[eightside,draw=black]{3}
(4.5,0) node[tenside,draw=black]{4}
(6,0) node[tenside,draw=black]{50}
(7.5,0) node[twelveside,draw=black]{6}
(9,0) node[twentyside,draw=black]{\scriptsize 7};
\end{tikzpicture}
\newpage
\newpage
\end{document}


The file dice.tex is the same as before, but now file random.tex contains the PRNG.

\makeatletter
% The following is taken from \cite{Numerical Recipes in C}.
% The resulting MAX_RAND = 134456
% Proven good statistics (relatively speaking) but designed for speed.
% Added 8 entry shuffle (32 seemed a bit much).
% Output through counter rand
%
% \randinit required for initialization
% \setrand{n} outputs rand between 0 and (n-1)
% \nextrand uses same scale computed by last \setrand

\newcounter{rand}% scaled random number
\newcounter{randk}% used by shuffle

\newcount\idum
\newcount\im
\newcount\ia
\newcount\ic
\im = 134456
\ia = 8121
\ic = 28411

\newcount\temp

\def\step@rand{% computes next value for \idum (internal only)
\global\multiply\idum by\ia
\global\temp = \idum% compute idum mod im
\global\divide\temp by\im
\global\multiply\temp by\im
}

\newcount\shuffle
\shuffle = 16807
\newcount\storeA
\newcount\storeB
\newcount\storeC
\newcount\storeD
\newcount\storeE
\newcount\storeF
\newcount\storeG
\newcount\storeH
\newcount\hold

\def\shuffle@rand{% random shuffle (internal only)
\step@rand
\c@randk = \idum
\divide\c@randk by\shuffle
\global\c@rand = \csname store\Alph{randk}\endcsname
\global\csname store\Alph{randk}\endcsname = \hold
\global\hold = \idum
}

\newcommand{\randinit}{% required to initialize PRNG
\global\idum = \day% seed uses number of minutes since start of month
\global\multiply\idum by 1440
\step@rand% warmup
\step@rand
\step@rand
\step@rand
\global\storeA = \idum% fill shuffle array
\step@rand
\global\storeB = \idum
\step@rand
\global\storeC = \idum
\step@rand
\global\storeD = \idum
\step@rand
\global\storeE = \idum
\step@rand
\global\storeF = \idum
\step@rand
\global\storeG = \idum
\step@rand
\global\storeH = \idum
\step@rand
\global\hold = \idum
}

\newcount\scale

\newcommand{\setrand}[1]{% scales rand between 0 and (#1 -1)
\global\scale = \@ne% To obtain unscaled numbers, use \setrand{0}
\ifnum #1 > \z@ \ifnum #1 < \im
\global\scale = \im% compute im/#1 rounded up
\global\divide\scale by #1\relax
\fi \fi
\shuffle@rand
\global\divide\c@rand by\scale
}

\newcommand{\nextrand}{% uses same scale as before
\shuffle@rand
\global\divide\c@rand by\scale
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\makeatother

• BTW, thanks to egreg for getting this to work in headers. Nov 21, 2013 at 23:44
• Huh, I wonder how this compares to the answer I accepted. I don't understand either set of code well enough to judge.... Nov 21, 2013 at 23:48
• The random functions of PGFmath reference the second edition of “Numeral Recipies in C” by William H. Press and Brian P. Flannery and Saul A. Teukolsky and William T. Vetterling, published by the Cambridge University Press. The source also references the lcg package which uses maybe (I didn’t check) the same algorithm, though with different parameters. Nov 22, 2013 at 2:07
• There is a whole table of numbers for the "quick and dirty" algorithm. The shuffle is used in their best algorithm, only with 32 array elements. I was worried I would be using up too many registers. I was primarily aiming for speed. Nov 22, 2013 at 4:29
• Unless you are doing a Monte Carlo simulation, the quality of the random numbers probably doesn't matter. The "quick and dirty" algorithm gets it name because it can be computed using 32 bit integers (directly). The shuffle is used to reduce periodic correlations. The main difference between my version and Tikz is that mine produces global integers instead of local floating point numbers. Nov 22, 2013 at 21:49