\ProvidesPackage{bfmi}


%%%%%%  USAGE  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%  \renewcommand\brutal[1]{\textbf{#1{}!}\\}
%%  \brute\Cfred
%%  \brute\Ccorpse
%%  \brute\Cjoneswolf
%%  \orderby{last \thenby first \thenby player}
%%  \bfmi
%%
%%  \debrute
%%  \brute\Cfred
%%  \brute\Cwilma
%%  \orderby{first \thenby last \thenby phone \thenby player}
%%  \renewcommand\brutal[1]{#1{char is sex}}
%%  \bfmi
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand\brute[1]{\expandafter\gdef\csname bfmi\string#1\endcsname{GOBBLE!}}
\newcommand\debrute{%
  \renewcommand\eachcharaction[1]%
    {\expandafter\let\csname bfmi\string##1\endcsname=\relax}
  \eachchar
}
\newcommand\brutal[1]{#1{}}  % default until overridden



% sneak into game.cls info combo magic (``BFMI@orderby'' combo)
\newcommand\orderby[1]{%
  \expandafter\gdef\csname COMP-BFMI@orderby\endcsname{#1}%
}
\orderby{last; first; middle; player}  % default until overridden


\newcommand\npl{}  % check name not taken
\newcount\npl

% check various names not taken
\newcommand\char@clump{}

\newcommand\thenby{}  % check name not taken
\newmuskip\thenby  % just want it to be not expanded by \edef
\newcommand\then@by{\thenby}

\newcommand\numberfy@end{\numberfy@end}
\newcommand\numberfy@tmp{}
\newcommand\numberfy@info[1]{%
  \renewcommand\numberfy@tmp{#1}%
  \ifx\numberfy@tmp\numberfy@end
    \?-100:\end@toss
    \let\numberfy@info\relax  % will only be done inside group
  \else
    \ifx\numberfy@tmp\then@by
      \?-10:\end@toss
      \npl=-1\relax  % skip leading spaces of next section
    \fi
    \ifcat A\noexpand#1\relax
      \ifnum\npl=1\relax \?-1:\end@toss \fi  % deal with any waiting space
      \npl=\lccode`#1\relax
      \expandafter\?\the\npl:\end@toss
      \npl=0\relax  % ok to do spaces
    \fi
    \if\noexpand#1\noexpand~\relax
      \ifnum\npl=0\relax\npl=1\relax\fi % have space waiting
    \fi
  \fi
  \numberfy@info
}

% check names not taken
\newcommand\if@comparison{} 
\newcommand\@comparisontrue{} 
\newcommand\@comparisonfalse{}
% ok, now use
\newif\if@comparison
% check names not used
\newcommand\compare@info{}
\newcommand\compare@delim{}
\newcommand\compare@next{}
% This should not be passed strings that are exactly equal!
\def\compare@info#1:#2\compare@delim#3:#4\compare@delim{%
  \let\compare@next\relax
  \ifnum#1>#3\relax
    \@comparisontrue
  \else
    \ifnum#1=#3\relax
      \def\compare@next{\compare@info#2\compare@delim#4\compare@delim}%
    \fi
  \fi
  \compare@next  % if #1<#3, quietly leave with comparison false (set outside)
}
      


\newcommand\clump@list{}  % check name not taken
\newcommand\order@info{}
\newcommand\order@num{}

\newdef\bfmi{%
  \gdef\clump@list{}%
  \gdef\eachcharaction##1{%
    \expandafter\ifx\csname bfmi\string##1\endcsname\relax\else
      % put this character in the clump list
      \add@to@macro\clump@list{\clump@char##1}%
      % initialize position to zero
      \expandafter\gdef\csname clump-position-\string##1\endcsname{0}%
      % put \orderby info into \order@info
      ##1{\def\order@info{BFMI@orderby}}%
      % refine \order@info by expanding regular macros in it
      \begingroup
        \aftergroup\edef \aftergroup\order@info
        \aftergroup{\relax \expandafter\?\order@info\end@toss \aftergroup}%
      \endgroup
      % refine \order@info by losing braces and turning spaces to tildes
      \begingroup
        \toss@without@braces  % provided by game.cls; set *locally* only
        \def\space@tossed{~}% % used by game.cls; set *locally* only
        \aftergroup\def \aftergroup\order@info
        \aftergroup{\relax \expandafter\?\order@info\end@toss \aftergroup}%
      \endgroup
      % refine \order@info into numerical sequence
      \begingroup
        \npl=-1\relax
        \aftergroup\tmp@str
        \aftergroup{\relax
        \expandafter\numberfy@info\order@info\numberfy@end
        \aftergroup}\relax
      \endgroup
      \expandafter\edef\csname clump-info-\string##1\endcsname{\the\tmp@str}%
    \fi
  }%
  % do it!
  \eachchar 
  % now we have the list for this clump, and the order info for each.  process!
  \begingroup
    \let\end@clump@list\relax
    \def\clump@char##1##2\end@clump@list{%
      \begingroup
        \edef\outer@clump@char{\csname clump-info-\string##1\endcsname}%
        \def\clump@char####1####2\end@clump@list{%
          \edef\inner@clump@char{\csname clump-info-\string####1\endcsname}%
          \ifx\inner@clump@char\outer@clump@char
            \@comparisontrue
          \else
            \@comparisonfalse
            \begingroup
              \aftergroup\compare@info
              \expandafter\?\inner@clump@char\end@toss
              \aftergroup\compare@delim
              \expandafter\?\outer@clump@char\end@toss
              \aftergroup\compare@delim
            \endgroup
          \fi
          \if@comparison
            \npl=\csname clump-position-\string##1\endcsname
            \advance\npl by 1\relax
            \expandafter\xdef\csname clump-position-\string##1\endcsname
              {\the\npl}%
          \else  % includes ties!
            \npl=\csname clump-position-\string####1\endcsname
            \advance\npl by 1\relax
            \expandafter\xdef\csname clump-position-\string####1\endcsname
              {\the\npl}%
          \fi
          ####2\end@clump@list  % inner tail-recurse
        }%
        ##2\end@clump@list  % start inner tail-recursion
      \endgroup
      ##2\end@clump@list  % outer tail-recurse
    }%
    \clump@list\end@clump@list  % start outer tail-recursion
    % chars now know their positions in the clump.  invert this mapping.
    \npl=-1\relax
    \def\clump@char##1{%
      \edef\num{\csname clump-position-\string##1\endcsname}%
      \expandafter\gdef\csname clumpchar-\num\endcsname{\brutal##1}%
      \ifnum\npl<\num\relax \npl=\num\relax \fi
    }%
    \clump@list
    % cause entries to be made, in order, after the group
    \loop \ifnum\npl>-1\relax
      \expandafter\aftergroup\csname clumpchar-\the\npl\endcsname
      \advance\npl by -1\relax
    \repeat
  \endgroup
}
