Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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
for(i = Skip to Sides)
{
    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.

share|improve this question
3  
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, … –  Qrrbrbirlbel Nov 10 '13 at 10:42
1  
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). –  John Kormylo Nov 11 '13 at 16:44

3 Answers 3

up vote 9 down vote accepted
+50

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}

Output

enter image description here


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).

enter image description here

share|improve this answer
1  
Even more Dang, you want an even distribution, not total randomness. That gonna be harder... –  Tom Bombadil Nov 12 '13 at 19:25
    
Is that what D&D dice look like? The kite seems unlikely. –  John Kormylo Nov 12 '13 at 23:01
    
@JohnKormylo: That's what they look like, see e.g. here. –  Tom Bombadil Nov 13 '13 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. –  John Kormylo Nov 13 '13 at 14:42
1  
Not on the dice I own ;) –  Tom Bombadil Nov 13 '13 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}
\chead{\csname dice\Roman{page}\endcsname}

%%%%%%%%%%%%%%%%%%%%%%%%% 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

This page intentionally left blank.
\newpage

This page intentionally left blank.

\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}}

dice

share|improve this answer
    
While it is possible to do calculations using LaTeX, WHY? Watch this until 0:45 ;-) –  Tom Bombadil Nov 14 '13 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. –  John Kormylo Nov 15 '13 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. –  Canageek Nov 19 '13 at 3:31
    
You could just roll dice if you want new random numbers, but it's your call. –  John Kormylo Nov 19 '13 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

%%%%%%%%%%%%%%%%%%%%%%%%% header macro %%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcount\test

\makeatletter
\newcommand{\makedice}% random dice and random throws
{\setrand{7}
\test = \c@rand
\ifnum\test=0{
 \setrand{4}
 \advance\c@rand by\@ne
 \begin{tikzpicture}
 \path node[fourside,draw=black]{\arabic{rand}};
 \end{tikzpicture}
}
\else \ifnum\test=1{
 \setrand{6}
 \advance\c@rand by\@ne
 \begin{tikzpicture}
 \path node[sixside,draw=black]{\arabic{rand}};
 \end{tikzpicture}
}
\else \ifnum\test=2{
 \setrand{8}
 \advance\c@rand by\@ne
 \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}
 \advance\c@rand by\@ne
 \begin{tikzpicture}
 \path node[twelveside,draw=black]{\arabic{rand}};
 \end{tikzpicture}
}
\else {
 \setrand{20}
 \advance\c@rand by\@ne
 \begin{tikzpicture}
 \path node[twentyside,draw=black]{\scriptsize\arabic{rand}};
 \end{tikzpicture}
} \fi \fi \fi \fi \fi \fi}
\makeatother

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

\begin{document}
\randinit
\pagestyle{fancy}
\chead{\makedice}
\setlength{\headheight}{1cm}

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
This page intentionally left blank.
\newpage
This page intentionally left blank.
\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\advance\idum by\ic
 \global\temp = \idum% compute idum mod im
 \global\divide\temp by\im
 \global\multiply\temp by\im
 \global\advance\idum by -\temp
}

\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
 \advance\c@randk by\@ne
 \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
 \global\advance\idum by \time
 \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\advance\scale by -\@ne
   \global\advance\scale by #1\relax
   \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
share|improve this answer
    
BTW, thanks to egreg for getting this to work in headers. –  John Kormylo Nov 21 '13 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.... –  Canageek Nov 21 '13 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. –  Qrrbrbirlbel Nov 22 '13 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. –  John Kormylo Nov 22 '13 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. –  John Kormylo Nov 22 '13 at 21:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.