% \iffalse
%% File: randomwalk.dtx Copyright (C) 2011-2013 Bruno Le Floch
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
%% license or (at your option) any later version.  The latest version
%% of this license is in the file
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% -----------------------------------------------------------------------
%
%<*driver|package>
%</driver|package>
%<*driver>
\RequirePackage[check-declarations]{expl3}
\documentclass[full]{l3doc}
\usepackage{randomwalk}
\usepackage{amsmath}
\begin{document}
  \DocInput{randomwalk.dtx}
\end{document}
%</driver>
% \fi
%
%
% \title{The \textsf{randomwalk} package: \\
%   customizable random walks using TikZ\thanks{This file has version
%     number 0.2c, last revised 2013-01-08.}}
% \author{Bruno Le Floch}
% \date{January 08, 2013}
%
% \maketitle
% \tableofcontents
%
% \begin{documentation}
%
% \begin{abstract}
%
% The \pkg{randomwalk} package draws random walks using TikZ. The
% following parameters can be customized:
% \begin{itemize}
%   \item The number of steps, of course.
%   \item The length of the steps, either a fixed length, or a length
%     taken at random from a given set.
%   \item The angle of each step, either taken at random from a given
%     set, or uniformly distributed.
% \end{itemize}
%
% \end{abstract}
%
%
% \section{How to use it}
%
% The \pkg{randomwalk} package has exactly one user command:
% \cs{RandomWalk}, which takes a list of key-value pairs as its
% argument. A few examples:
% \begin{verbatim}
% \RandomWalk {number = 100, length = {4pt, 10pt}}
% \RandomWalk {number = 100, angles = {0,60,120,180,240,300}, degree}
% \RandomWalk {number = 100, length = 2em,
%   angles = {0,10,20,-10,-20}, degree, angles-relative}
% \end{verbatim}
% The simplest is to give a list of all the keys, and their meaning:
% \begin{itemize}
%   \item \texttt{number}: the number of steps (default \(10\))
%   \item \texttt{length}: the length of each step: either one dimension
%     (\emph{e.g.}, |1em|), or a comma-separated list of dimensions
%     (\emph{e.g.}, |{2pt, 5pt}|), by default |10pt|. The length of each
%     step is a random element in this set of possible dimensions.
%   \item \texttt{angles}: the polar angle for each step: a
%     comma-separated list of angles, and each step takes a random angle
%     among the list. If this is not specified, then the angle is
%     uniformly distributed along the circle.
%   \item \texttt{degree} or \texttt{degrees}: specify that the angles
%     are given in degrees.
%   \item \texttt{angles-relative}: instead of being absolute, the
%     angles are relative to the direction of the previous step.
% \end{itemize}
%
% \begin{figure}
%   \begin{center}
%     \framebox{\RandomWalk {number = 400, length = {4pt, 10pt}}}
%     \caption{The result of \texttt{RandomWalk\{number\ =\ 400,\
%         length\ =\ \{4pt,\ 10pt\}\}}: a \(400\) steps long walk, where
%       each step has one of two lengths.}
%   \end{center}
% \end{figure}
%
% \begin{figure}
%   \begin{center}
%     \framebox{\RandomWalk{number = 100, angles =
%         {0,60,120,180,240,300}, degrees}}
%     \caption{The result of \texttt{\string\RandomWalk\{number\ =\
%         100,\ angles\ =\ \{0,60,120,180,240,300\}, degrees\}}: angles
%       are constrained.}
%   \end{center}
% \end{figure}
%
% \begin{figure}
%   \begin{center}
%     \framebox{\RandomWalk {number = 40, length = 1em, angles =
%         {0,15,30,-15,-30}, degree, angles-relative}}
%     \caption{A last example: \texttt{\string\RandomWalk\ \{number\ =\
%         100,\ length\ =\ 2em,\ angles\ =\ \{0,10,20,-10,-20\},\
%         degree,\ angles-relative\}}}
%   \end{center}
% \end{figure}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{randomwalk} implementation}
%
% \subsection{Packages}
%
% The whole \pkg{expl3} bundle is loaded first.
%
%<*package>
%    \begin{macrocode}
%<@@=randomwalk>
%    \end{macrocode}
%
%    \begin{macrocode}
\RequirePackage {expl3} [2012/08/14]
\ProvidesExplPackage
  {randomwalk.sty} {2013/01/08} {0.2c} {Customizable random walks using TikZ}
\RequirePackage {xparse} [2012/08/14]
%    \end{macrocode}
%
% I use some \LaTeXe{} packages: \pkg{TikZ}, for figures, and \pkg{lcg}
% for random numbers.
%    \begin{macrocode}
\RequirePackage {tikz}
%    \end{macrocode}
%
% \pkg{lcg} needs to know the smallest and biggest random numbers that
% it should produce, which we take to be $0$ and $\cs{c_@@_lcg_last_int}
% = 2^{31}-2$.  It will then store them in \cs{c@lcg@rand}: the |\c@| is
% there because of how \LaTeXe{} defines counters. To make it clear that
% |\c| has a very special meaning here, I do not follow \LaTeX3 naming
% conventions.
%
% It seems that the \pkg{lcg} package has to be loaded after the
% document class, hence we do it \cs{AtBeginDocument}.
%    \begin{macrocode}
\int_const:Nn \c_@@_lcg_last_int { \c_max_int - \c_one }
\AtBeginDocument
  {
    \RequirePackage
      [
        first= \c_zero ,
        last = \c_@@_lcg_last_int ,
        counter = lcg@rand
      ]
      { lcg }
    \rand % This \rand avoids some very odd bug.
  }
%    \end{macrocode}
%
% \subsection{Variables}
%
% \begin{variable}{\l_@@_step_number_int}
%   The number of steps requested by the caller.
%    \begin{macrocode}
\int_new:N \l_@@_step_number_int
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_relative_angles_bool}
%   Booleans for whether angles are relative (keyval option).
%    \begin{macrocode}
\bool_new:N \l_@@_relative_angles_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_revert_random_bool}
%   Booleans for whether to revert the random seed to its original value
%   or keep the last value reached at the end of a random path.
%    \begin{macrocode}
\bool_new:N \l_@@_revert_random_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_rand_angle:, \@@_rand_length:}
%   Set the \cs{l_@@_angle_fp} and \cs{l_@@_length_fp} of the next step,
%   most often randomly.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_rand_angle: { }
\cs_new_protected_nopar:Npn \@@_rand_length: { }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_angle_fp, \l_@@_length_fp}
%   Angle and length of the next step.
%    \begin{macrocode}
\fp_new:N \l_@@_angle_fp
\fp_new:N \l_@@_length_fp
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_old_x_fp, \l_@@_old_y_fp}
% \begin{variable}{\l_@@_new_x_fp, \l_@@_new_y_fp}
%   Coordinates of the two ends of each step: each \cs{draw} statement
%   goes from the |_old| point to the |_new| point.  See
%   \cs{@@_step_draw:}.
%    \begin{macrocode}
\fp_new:N \l_@@_old_x_fp
\fp_new:N \l_@@_old_y_fp
\fp_new:N \l_@@_new_x_fp
\fp_new:N \l_@@_new_y_fp
%    \end{macrocode}
% \end{variable}
% \end{variable}
%
% \begin{variable}{\l_@@_angles_seq, \l_@@_lengths_seq}
%   Sequences containing all allowed angles and lengths.
%    \begin{macrocode}
\seq_new:N \l_@@_angles_seq
\seq_new:N \l_@@_lengths_seq
%    \end{macrocode}
% \end{variable}
%
% \subsection{How the key-value list is treated}
%
% \begin{macro}{\RandomWalk}
%   The only user command is \cs{RandomWalk}: it simply does the setup,
%   and calls the internal macro \cs{@@_walk:}.
%    \begin{macrocode}
\DeclareDocumentCommand \RandomWalk { m }
  {
    \@@_set_defaults:
    \keys_set:nn { randomwalk } { #1 }
    \@@_walk:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_defaults:}
%   Currently, the package treats the length of steps, and the angle,
%   completely independently.  The function \cs{@@_rand_length:}
%   contains the action that decides the length of the next step, while
%   the function \cs{@@_rand_angle:} pertains to the angle.
%
%   \cs{@@_set_defaults:} sets the default values before processing the
%   user's key-value input.
%    \begin{macrocode}
\cs_new:Npn \@@_set_defaults:
  {
    \int_set:Nn \l_@@_step_number_int {10}
    \cs_gset_protected_nopar:Npn \@@_rand_angle:
      { \@@_fp_set_rand:Nnn \l_@@_angle_fp { - pi } { pi } }
    \cs_gset_protected_nopar:Npn \@@_rand_length:
      { \fp_set:Nn \l_@@_length_fp {10} }
    \bool_set_false:N \l_@@_revert_random_bool
    \bool_set_false:N \l_@@_relative_angles_bool
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\keys_define:nn}
%   We introduce the keys for the package.
%    \begin{macrocode}
\keys_define:nn { randomwalk }
  {
    number .value_required: ,
    length .value_required: ,
    angles .value_required: ,
    number .int_set:N = \l_@@_step_number_int ,
    length .code:n =
      {
        \seq_set_split:Nnn \l_@@_lengths_seq { , } {#1}
        \seq_set_map:NNn \l_@@_lengths_seq
          \l_@@_lengths_seq { \dim_to_fp:n {##1} }
        \int_compare:nNnTF { \seq_count:N \l_@@_lengths_seq } = {1}
          {
            \cs_gset_protected_nopar:Npn \@@_rand_length:
              { \fp_set:Nn \l_@@_length_fp {#1} }
          }
          {
            \cs_gset_protected_nopar:Npn \@@_rand_length:
              {
                \@@_fp_set_rand_seq_item:NN
                  \l_@@_length_fp \l_@@_lengths_seq
              }
          }
      } ,
    angles .code:n  =
      {
        \seq_set_split:Nnn \l_@@_angles_seq { , } {#1}
        \cs_gset_protected_nopar:Npn \@@_rand_angle:
          {
            \bool_if:NTF \l_@@_relative_angles_bool
              { \@@_fp_add_rand_seq_item:NN }
              { \@@_fp_set_rand_seq_item:NN }
              \l_@@_angle_fp \l_@@_angles_seq
          }
      } ,
    degree .code:n  =
      { \@@_radians_from_degrees:N \l_@@_angles_seq } ,
    degrees .code:n =
      { \@@_radians_from_degrees:N \l_@@_angles_seq } ,
    angles-relative .code:n =
      { \bool_set_true:N \l_@@_relative_angles_bool } ,
    revert-random .bool_set:N = \l_@@_revert_random_bool ,
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_radians_from_degrees:N}
%   Helper macro to convert all items in |#1| to degrees.
%    \begin{macrocode}
\cs_new:Npn \@@_radians_from_degrees:N #1
  { \seq_set_map:NNn #1 #1 { \fp_eval:n { ##1 deg } } }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Drawing}
%
% \begin{macro}{\@@_walk:}
%   We are ready to define \cs{@@_walk:}, which draws a \pkg{TikZ}
%   picture of a random walk with the parameters set up by the
%   \texttt{keys}.  We reset all the coordinates to zero originally.
%   Then we draw the relevant \pkg{TikZ} picture by repeatedly calling
%   \cs{@@_step_draw:}.
%    \begin{macrocode}
\cs_new:Npn \@@_walk:
  {
    \begin{tikzpicture}
      \fp_zero:N \l_@@_old_x_fp
      \fp_zero:N \l_@@_old_y_fp
      \fp_zero:N \l_@@_new_x_fp
      \fp_zero:N \l_@@_new_y_fp
      \prg_replicate:nn { \l_@@_step_number_int } { \@@_step_draw: }
      \bool_if:NF \l_@@_revert_random_bool
        { \int_gset_eq:NN \cr@nd \cr@nd }
    \end{tikzpicture}
  }
%    \end{macrocode}
%   \cs{cr@nd} is internal to the lcg package.
% \end{macro}
%
% \begin{macro}{\@@_step_draw:}
%   \cs{@@_step_draw:} calls \cs{@@_rand_length:} and
%   \cs{@@_rand_angle:} to determine the length and angle of the new
%   step.  This is then converted to cartesian coordinates and added to
%   the previous end-point.  Finally, we call \pkg{TikZ}'s \cs{draw} to
%   produce a line from the |_old| to the |_new| point.
%    \begin{macrocode}
\cs_new:Npn \@@_step_draw:
  {
    \@@_rand_length:
    \@@_rand_angle:
    \fp_set_eq:NN \l_@@_old_x_fp \l_@@_new_x_fp
    \fp_set_eq:NN \l_@@_old_y_fp \l_@@_new_y_fp
    \fp_add:Nn \l_@@_new_x_fp { \l_@@_length_fp * cos \l_@@_angle_fp }
    \fp_add:Nn \l_@@_new_y_fp { \l_@@_length_fp * sin \l_@@_angle_fp }
    \draw ( \fp_to_dim:N \l_@@_old_x_fp, \fp_to_dim:N \l_@@_old_y_fp )
       -- ( \fp_to_dim:N \l_@@_new_x_fp, \fp_to_dim:N \l_@@_new_y_fp );
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{On random numbers and items}
%
% For random numbers, the interface of \pkg{lcg} is not quite enough, so
% we provide our own \LaTeX3-y functions.  Also, this will allow us to
% change quite easily our source of random numbers.
%
% \begin{macro}[aux]{\@@_int_set_rand:Nnn}
%   Sets the integer register |#1| equal to a random integer between
%   |#2| and |#3| inclusive.
%    \begin{macrocode}
\cs_new:Npn \@@_int_set_rand:Nnn #1#2#3
  {
    \rand
    \int_set:Nn #1 { #2 + \int_mod:nn {\c@lcg@rand} { #3 + 1 - (#2) } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_fp_set_rand:Nnn, \@@_fp_add_rand:Nnn}
% \begin{macro}[aux]{\@@_fp_set_rand_aux:NNnn}
%   We also need floating point random numbers, both assigned and added
%   to the variable |#1| (well, |#2| of the auxiliary).
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_fp_set_rand:Nnn
  { \@@_fp_set_rand_aux:NNnn \fp_set:Nn }
\cs_new_nopar:Npn \@@_fp_add_rand:Nnn
  { \@@_fp_set_rand_aux:NNnn \fp_add:Nn }
\cs_new:Npn \@@_fp_set_rand_aux:NNnn #1#2#3#4
  {
    \rand
    #1 #2 { #3 + (#4 - (#3)) * \c@lcg@rand / \c_@@_lcg_last_int }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[aux]{\@@_fp_set_rand_seq_item:NN, \@@_fp_add_rand_seq_item:NN}
% \begin{macro}[aux]{\@@_fp_set_rand_item_aux:NNNNN}
%   We can now pick an element at random from a sequence, and either
%   assign it or add it to the fp variable |#4|.  The same auxiliary
%   could be used for picking random items from other types of lists.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_fp_set_rand_seq_item:NN
  { \@@_fp_set_rand_item_aux:NNNNN \fp_set:Nn \seq_item:Nn \seq_count:N }
\cs_new_protected_nopar:Npn \@@_fp_add_rand_seq_item:NN
  { \@@_fp_set_rand_item_aux:NNNNN \fp_add:Nn \seq_item:Nn \seq_count:N }
\cs_new_protected:Npn \@@_fp_set_rand_item_aux:NNNNN #1#2#3#4#5
  {
    \rand
    #1 #4 { #2 #5 { 1 + \int_mod:nn { \c@lcg@rand } { #3 #5 } } }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \endinput
