%%
%% This is file `solvesudoku.sty',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% sudokubundle.dtx  (with options: `solve')
%% 
%% -----------------------------------------------------------------
%%   Author: Peter Wilson (herries dot press at earthlink dot net)
%%           Herries Press
%%   Copyright 2006 Peter R. Wilson
%% 
%%   This work may be distributed and/or modified under the
%%   conditions of the LaTeX Project Public License, either
%%   version 1.3 of this license or (at your option) any
%%   later version.
%%   The latest version of the license is in
%%      http://www.latex-project.org/lppl.txt
%%   and version 1.3 or later is part of all distributions of
%%   LaTeX version 2003/06/01 or later.
%% 
%%   This work has the LPPL maintenance status "author-maintained".
%% 
%%   This work consists of the files listed in the README file.
%% -----------------------------------------------------------------
%% 
%%%% solvethem.tex   Solve Sudoku files
%%%%                 Peter Wilson
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{solvesudoku}[2006/02/16 v1.0 solve sudoku puzzles]
\RequirePackage{printsudoku}

\newcommand{\commentary}[1]{\typeout{#1}}

%%% too many counts, maybe they should be reduced
\newcount\s@lcnta     % a cell number
\newcount\solcnt      % number of solved cells
\newcount\settonumcnt
\newcount\tenscnt
\newcount\tempcntz
\newcount\tempcnty
\newcount\tmpsetctr
\newcount\tmpsetansctr
\newcount\boxctr
\newcount\sumctr
\newcount\toprangectr
\newcount\lonecellctr
\newcount\reducedctr
\newcount\numlistctr
\newcount\difficultyctr
\newcount\s@dtempcnta
\newcount\s@dtempcntb
\newcount\s@dtemploopcnta
\newcount\maxrangectr
\newcount\asetctr
\newcount\secondctr
\newcount\digitictr
\newcount\digitiictr
\newcount\numdigitsctr
\newcount\numcluesctr

%%% \iffirsts@dclue% defined in printsudoku package
\newif\iffirstchar
\newif\ifnotgotthechar
\newif\ifsetchanged
\newif\ifchanged
\newif\ifanychange
\newif\iflonerchanged
\newif\ifstilldigits
\newif\ifkeepon
\newif\ifpairchanged

%% create and use a numbered count
%% we'll use 81 of these, one for each cell in the grid
\newcommand*{\newknt}[1]{\expandafter\newcount\csname #1\endcsname}
\newcommand*{\useknt}[1]{\csname #1\endcsname}
%% create potential answer sets
\newcommand*{\createsudsets}{%
\global\s@lcnta\@ne
\global\solcnt\z@
\loop
  \ifnum\s@lcnta<82\relax
  \newknt{s@lans\the\s@lcnta}%
  \advance\s@lcnta\@ne
\repeat}
\createsudsets

%% initialise potential answer sets
\newcommand*{\initialisesuddata}{\bgroup
\global\s@lcnta\@ne
\global\solcnt\z@
\global\difficultyctr\z@
\global\numcluesctr\z@
\loop
  \ifnum\s@lcnta<82\relax
  \global\useknt{s@lans\the\s@lcnta}=111111111\relax
  \advance\s@lcnta\@ne
\repeat
\egroup}

%%%%%%%%%%%%%%%%%%%%%%%% utility macros for `binary solution sets' %%%%%%%%%%%%%%%%

%%\settonum{110011...}{cnt}
%% converts a potential solution set to a number ([11....1] -> 12...9)
%% returns the input if it is negative ([-3] -> -3)
%% returns a negative number if the set represents a single digit ([10] -> -8)
\newcommand*{\settonum}[2]{%
  \settonumcnt=#1\relax
  \tempcnty=\z@
  \tenscnt=\@ne
  \ifnum\settonumcnt<\z@ % just return the number
    \tempcnty=\settonumcnt
    #2=\tempcnty
  \else
    \ifodd\settonumcnt    % 9 flagged
      \tempcntz=9\relax
      \multiply\tempcntz \tenscnt
      \advance \tempcnty by \tempcntz
      \multiply\tenscnt 10\relax
    \fi
    \divide\settonumcnt by 10\relax
    \ifodd\settonumcnt   % 8 flagged
      \tempcntz=8\relax
      \multiply\tempcntz \tenscnt
      \advance \tempcnty \tempcntz
      \multiply\tenscnt 10\relax
    \fi
    \divide\settonumcnt by 10\relax
    \ifodd\settonumcnt   % 7 flagged
      \tempcntz=7\relax
      \multiply\tempcntz \tenscnt
      \advance \tempcnty \tempcntz
      \multiply\tenscnt 10\relax
    \fi
    \divide\settonumcnt by 10\relax
    \ifodd\settonumcnt   % 6 flagged
      \tempcntz=6\relax
      \multiply\tempcntz \tenscnt
      \advance \tempcnty \tempcntz
      \multiply\tenscnt 10\relax
    \fi
    \divide\settonumcnt by 10\relax
    \ifodd\settonumcnt   % 5 flagged
      \tempcntz=5\relax
      \multiply\tempcntz \tenscnt
      \advance \tempcnty \tempcntz
      \multiply\tenscnt 10\relax
    \fi
    \divide\settonumcnt by 10\relax
    \ifodd\settonumcnt   % 4 flagged
      \tempcntz=4\relax
      \multiply\tempcntz \tenscnt
      \advance \tempcnty \tempcntz
      \multiply\tenscnt 10\relax
    \fi
    \divide\settonumcnt by 10\relax
    \ifodd\settonumcnt   % 3 flagged
      \tempcntz=3\relax
      \multiply\tempcntz \tenscnt
      \advance \tempcnty \tempcntz
      \multiply\tenscnt 10\relax
    \fi
    \divide\settonumcnt by 10\relax
    \ifodd\settonumcnt   % 2 flagged
      \tempcntz=2\relax
      \multiply\tempcntz \tenscnt
      \advance \tempcnty \tempcntz
      \multiply\tenscnt 10\relax
    \fi
    \divide\settonumcnt by 10\relax
    \ifodd\settonumcnt   % 1 flagged
      \tempcntz=1\relax
      \multiply\tempcntz \tenscnt
      \advance \tempcnty \tempcntz
%%      \multiply\tenscnt 10\relax
    \fi
    \ifnum \tempcnty<10
      \ifnum\tempcnty>\z@
        \tempcnty = -\tempcnty
      \fi
    \fi
    #2=\tempcnty
\fi}

%%\numofnuminset{digit}{set}{returnctr}
%%  returns the number of times digit is represented in the set
%% e.g. if the set is [200000013] then 1 -> 2, 2 -> 0,... 8 -> 1, 9 -> 3
\newcommand*{\numofnuminset}[3]{%
  \tmpsetctr=#2\relax
  \tmpsetansctr=\tmpsetctr
  \ifnum\tmpsetctr<\z@% solution, not a set
    \tmpsetansctr=\z@
  \else
    \ifcase #1\relax
    \or               % 1
      \divide\tmpsetansctr by 100000000\relax
    \or               % 2
      \divide\tmpsetansctr by 10000000\relax
      \tmpsetctr=\tmpsetansctr
      \divide\tmpsetctr 10\relax \multiply\tmpsetctr 10\relax
      \advance\tmpsetansctr -\tmpsetctr
    \or               % 3
      \divide\tmpsetansctr by 1000000\relax
      \tmpsetctr=\tmpsetansctr
      \divide\tmpsetctr 10\relax \multiply\tmpsetctr 10\relax
      \advance\tmpsetansctr -\tmpsetctr
    \or               % 4
      \divide\tmpsetansctr by 100000\relax
      \tmpsetctr=\tmpsetansctr
      \divide\tmpsetctr 10\relax \multiply\tmpsetctr 10\relax
      \advance\tmpsetansctr -\tmpsetctr
    \or               % 5
      \divide\tmpsetansctr by 10000\relax
      \tmpsetctr=\tmpsetansctr
      \divide\tmpsetctr 10\relax \multiply\tmpsetctr 10\relax
      \advance\tmpsetansctr -\tmpsetctr
    \or               % 6
      \divide\tmpsetansctr by 1000\relax
      \tmpsetctr=\tmpsetansctr
      \divide\tmpsetctr 10\relax \multiply\tmpsetctr 10\relax
      \advance\tmpsetansctr -\tmpsetctr
    \or               % 7
      \divide\tmpsetansctr by 100\relax
      \tmpsetctr=\tmpsetansctr
      \divide\tmpsetctr 10\relax \multiply\tmpsetctr 10\relax
      \advance\tmpsetansctr -\tmpsetctr
    \or               % 8
      \divide\tmpsetansctr by 10\relax
      \tmpsetctr=\tmpsetansctr
      \divide\tmpsetctr 10\relax \multiply\tmpsetctr 10\relax
      \advance\tmpsetansctr -\tmpsetctr
    \or               % 9
      \tmpsetctr=\tmpsetansctr
      \divide\tmpsetctr 10\relax \multiply\tmpsetctr 10\relax
      \advance\tmpsetansctr -\tmpsetctr
    \else             % error
      \tmpsetansctr=\z@
    \fi
  \fi
  #3=\tmpsetansctr}

%%\deletenumfromset{digit}{set}{returnctr}
%% deletes num from the [set], returning the modified set or a -ve number if
%% the digit was the only member.
%% e.g., 9 from [...11] -> [...10], 8 from [0...010] -> -8
\newcommand*{\deletenumfromset}[3]{
  \global\setchangedfalse
  \tmpsetctr=#2\relax
  \tmpsetansctr=#2\relax
\ifnum\tmpsetctr<\z@ % represents a solved number, do nothing
\else
  \ifcase #1\relax
  \or               % 1
    \divide\tmpsetctr by 100000000\relax
    \ifodd\tmpsetctr%                it's there
      \advance\tmpsetansctr -100000000\relax
      \global\setchangedtrue
    \fi
  \or               % 2
    \divide\tmpsetctr by 10000000\relax
    \ifodd\tmpsetctr%                it's there
      \advance\tmpsetansctr -10000000\relax
      \global\setchangedtrue
    \fi
  \or               % 3
    \divide\tmpsetctr by 1000000\relax
    \ifodd\tmpsetctr%                it's there
      \advance\tmpsetansctr -1000000\relax
      \global\setchangedtrue
    \fi
  \or               % 4
    \divide\tmpsetctr by 100000\relax
    \ifodd\tmpsetctr%                it's there
      \advance\tmpsetansctr -100000\relax
      \global\setchangedtrue
    \fi
  \or               % 5
    \divide\tmpsetctr by 10000\relax
    \ifodd\tmpsetctr%                it's there
      \advance\tmpsetansctr -10000\relax
      \global\setchangedtrue
    \fi
  \or               % 6
    \divide\tmpsetctr by 1000\relax
    \ifodd\tmpsetctr%                it's there
      \advance\tmpsetansctr -1000\relax
      \global\setchangedtrue
    \fi
  \or               % 7
    \divide\tmpsetctr by 100\relax
    \ifodd\tmpsetctr%                it's there
      \advance\tmpsetansctr -100\relax
      \global\setchangedtrue
    \fi
  \or               % 8
    \divide\tmpsetctr by 10\relax
    \ifodd\tmpsetctr%                it's there
      \advance\tmpsetansctr -10\relax
      \global\setchangedtrue
    \fi
  \or               % 9
    \ifodd\tmpsetctr%                it's there
      \advance\tmpsetansctr -1\relax
      \global\setchangedtrue
    \fi
  \fi
\fi
  #3=\tmpsetansctr}

%% typeset current answers plus potential answer digits
\newcommand*{\displaystatus}{%
\begin{tabular}{||c|c|c||c|c|c||c|c|c||}\hline\hline
\settonum{\the\useknt{s@lans1}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans2}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans3}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans4}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans5}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans6}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans7}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans8}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans9}}{\s@dtempcnta}\the\s@dtempcnta \\ \hline
\settonum{\the\useknt{s@lans10}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans11}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans12}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans13}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans14}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans15}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans16}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans17}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans18}}{\s@dtempcnta}\the\s@dtempcnta \\ \hline
\settonum{\the\useknt{s@lans19}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans20}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans21}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans22}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans23}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans24}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans25}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans26}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans27}}{\s@dtempcnta}\the\s@dtempcnta \\ \hline\hline
\settonum{\the\useknt{s@lans28}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans29}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans30}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans31}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans32}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans33}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans34}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans35}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans36}}{\s@dtempcnta}\the\s@dtempcnta \\ \hline
\settonum{\the\useknt{s@lans37}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans38}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans39}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans40}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans41}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans42}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans43}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans44}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans45}}{\s@dtempcnta}\the\s@dtempcnta \\ \hline
\settonum{\the\useknt{s@lans46}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans47}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans48}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans49}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans50}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans51}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans52}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans53}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans54}}{\s@dtempcnta}\the\s@dtempcnta \\ \hline\hline
\settonum{\the\useknt{s@lans55}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans56}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans57}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans58}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans59}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans60}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans61}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans62}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans63}}{\s@dtempcnta}\the\s@dtempcnta \\ \hline
\settonum{\the\useknt{s@lans64}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans65}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans66}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans67}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans68}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans69}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans70}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans71}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans72}}{\s@dtempcnta}\the\s@dtempcnta \\ \hline
\settonum{\the\useknt{s@lans73}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans74}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans75}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans76}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans77}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans78}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans79}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans80}}{\s@dtempcnta}\the\s@dtempcnta &
\settonum{\the\useknt{s@lans81}}{\s@dtempcnta}\the\s@dtempcnta \\ \hline\hline
\end{tabular}}

%%%%%%%%%%%%%%%%%%%% get the problem and initialise the solution %%%%%%%%%

%% read the problem and initialise the problem (solution)
\newcommand*{\getproblem}[1]{\bgroup
  \initialisesuddata
  \global\solcnt\z@
  \immediate\closein\s@dread
  \immediate\openin\s@dread=#1
  \initialsoln
  \typeout{Sudoku problem #1, \the\solcnt\space initial clues}
\egroup}

%% insert the clues from the input game file
\newcommand*{\initialsoln}{%
  \firsts@dcluetrue
  \s@dnrow\@ne
  \s@lcnta\@ne
  \loop
     \ifnum\s@dnrow<10\relax
     \read\s@dread to \s@dline
     \firsts@dcluetrue
     \s@dncol\@ne
     \dos@dinitialcols
     \advance\s@dnrow\@ne
  \repeat
  \immediate\closein\s@dread}

%% insert the clues from one line of the game file
\newcommand*{\dos@dinitialcols}{\bgroup
  \loop
    \ifnum\s@dncol<10\relax
    \fixentry
    \advance\s@dncol\@ne
  \repeat
\egroup}

%% insert a clue from the current line of the game file
\newcommand*{\fixentry}{%
  \iffirsts@dclue
    \expandafter\splitoff\expandafter{\s@dline}%
    \global\firsts@dcluefalse
  \else
    \expandafter\splitoff\expandafter{\restchars}%
  \fi
  \ifx\s@dfstop\istchar
  \else
    \global\useknt{s@lans\the\s@lcnta}=-\istchar
    \global\advance\solcnt\@ne
    \global\advance\numcluesctr\@ne
  \fi
  \global\advance\s@lcnta\@ne}

%% Eliminate a solution digit from its row, column and box.
%% This may result in some new solutions.
\newcommand*{\reduceacell}{\bgroup
  \ifnum\useknt{s@lans\the\s@lcnta}<\z@   % solved cell
    \s@dtempcnta=-\useknt{s@lans\the\s@lcnta}
%% get the col, row and box numbers
    \tempcnty=\s@lcnta       % M in the formulae
    \advance\tempcnty\m@ne   \divide\tempcnty 9\relax
    \tempcntz=\tempcnty      \multiply\tempcntz 9\relax
    \s@dcolpos=\s@lcnta         \advance\s@dcolpos -\tempcntz % col
    \s@drowpos\tempcntz         \advance\s@drowpos\@ne          % row
    \boxctr=\tempcnty        % box
    \divide\boxctr\thr@@     \multiply\boxctr 27\relax
    \tempcnty=\s@lcnta       % reuse \tempcnty
    \advance\tempcnty\m@ne   \advance\tempcnty -\tempcntz
    \divide\tempcnty\thr@@   \multiply\tempcnty \thr@@
    \advance\boxctr\tempcnty \advance\boxctr \@ne
%% reduce the row, column, and the box
    \reducerow{\the\s@drowpos}{\the\s@dtempcnta}
    \reducecol{\the\s@dcolpos}{\the\s@dtempcnta}
    \reducebox{\the\boxctr}{\the\s@dtempcnta}
  \fi
\egroup}

%% \reducerow{rowcellnumber}{digit}
%% simple reduction for digit in a row
\newcommand*{\reducerow}[2]{\bgroup
  \s@dncol=#1\relax
  \toprangectr=\s@dncol
  \advance\toprangectr 9\relax
  \bgroup
  \loop
    \ifnum\s@dncol<\toprangectr
    \deletenumfromset{#2}{\the\useknt{s@lans\the\s@dncol}}{\reducedctr}
    \ifsetchanged
      \global\changedtrue
      \settonum{\the\reducedctr}{\numlistctr}
      \ifnum\numlistctr<10\relax
        \global\advance\solcnt\@ne
\commentary{\the\solcnt\space solved
            (\the\s@dncol\space = \the\numlistctr\space in row starting #1)}%
        \global\useknt{s@lans\the\s@dncol}=\numlistctr
      \else
        \global\useknt{s@lans\the\s@dncol}=\reducedctr
      \fi
    \fi
    \advance\s@dncol\@ne
  \repeat
  \egroup
\egroup}

%% \reducecol{colcellnumber}{digit}
%% simple reduction of a digit in a column
\newcommand*{\reducecol}[2]{\bgroup
  \s@dnrow=#1\relax
  \toprangectr=\s@dnrow
  \advance\toprangectr 73\relax
  \bgroup
  \loop
    \ifnum\s@dnrow<\toprangectr
    \deletenumfromset{#2}{\the\useknt{s@lans\the\s@dnrow}}{\reducedctr}
    \ifsetchanged
      \global\changedtrue
      \settonum{\the\reducedctr}{\numlistctr}
      \ifnum\numlistctr<10\relax
          \global\advance\solcnt\@ne
\commentary{\the\solcnt\space solved
            (\the\s@dnrow\space = \the\numlistctr\space in column starting #1)}%
          \global\useknt{s@lans\the\s@dnrow}=\numlistctr
      \else
        \global\useknt{s@lans\the\s@dnrow}=\reducedctr
      \fi
    \fi
    \advance\s@dnrow 9\relax
  \repeat
  \egroup
\egroup}

%% \reducebox{boxcellnumber}{digit}
%% simple reduction of a digit in a box
\newcommand*{\reducebox}[2]{\bgroup
  \s@dncol=#1\relax
  \toprangectr=\s@dncol
  \advance\toprangectr \thr@@
  \bgroup
  \loop
    \ifnum\s@dncol<\toprangectr
    \s@dnrow=\s@dncol
    \deletenumfromset{#2}{\the\useknt{s@lans\the\s@dnrow}}{\reducedctr}
    \ifsetchanged
      \global\changedtrue
      \settonum{\the\reducedctr}{\numlistctr}
      \ifnum\numlistctr<10\relax
          \global\advance\solcnt\@ne
\commentary{\the\solcnt\space solved
            (\the\s@dnrow\space = \the\numlistctr\space in box starting #1)}%
          \global\useknt{s@lans\the\s@dnrow}=\numlistctr
      \else
        \global\useknt{s@lans\the\s@dnrow}=\reducedctr
      \fi
    \fi
    \advance\s@dnrow 9\relax
    \deletenumfromset{#2}{\the\useknt{s@lans\the\s@dnrow}}{\reducedctr}
    \ifsetchanged
      \global\changedtrue
      \settonum{\the\reducedctr}{\numlistctr}
      \ifnum\numlistctr<10\relax
          \global\advance\solcnt\@ne
\commentary{\the\solcnt\space solved
            (\the\s@dnrow\space = \the\numlistctr\space in box starting #1)}%
          \global\useknt{s@lans\the\s@dnrow}=\numlistctr
      \else
        \global\useknt{s@lans\the\s@dnrow}=\reducedctr
      \fi
    \fi
    \advance\s@dnrow 9\relax
    \deletenumfromset{#2}{\the\useknt{s@lans\the\s@dnrow}}{\reducedctr}
    \ifsetchanged
      \global\changedtrue
      \settonum{\the\reducedctr}{\numlistctr}
      \ifnum\numlistctr<10\relax
          \global\advance\solcnt\@ne
\commentary{\the\solcnt\space solved
            (\the\s@dnrow\space = \the\numlistctr\space in box starting #1)}%
          \global\useknt{s@lans\the\s@dnrow}=\numlistctr
      \else
        \global\useknt{s@lans\the\s@dnrow}=\reducedctr
      \fi
    \fi
    \advance\s@dncol \@ne
  \repeat
  \egroup
\egroup}

%% loop over every cell, removing solution digits from the potential sets
%% in the cell's row, column and box.
\newcommand*{\reduceallcells}{\bgroup
  \ifnum\difficultyctr<\@ne
    \global\difficultyctr\@ne
  \fi
  \s@lcnta\@ne
  \global\changedfalse
  \loop
    \ifnum\s@lcnta<82\relax
    \reduceacell
    \advance\s@lcnta\@ne
  \repeat
\egroup}

\newcommand*{\keepreducing}{%
  \anychangetrue
  \keepontrue
  \loop
    \ifkeepon
    \keepreducingcells
    \ifnum\solcnt<81\relax
%%%      \advance\difficultyctr 4\relax
      \reduceloners
    \fi
    \anychangefalse
    \iflonerchanged
      \anychangetrue
    \fi
    \ifanychange\else
      \ifnum\solcnt<81\relax
%%%        \advance\difficultyctr 8\relax
        \pairchangedfalse
        \reducepairs
        \ifpairchanged
          \anychangetrue
        \fi
      \fi
    \fi
    \checkkeepon
  \repeat
  \ifnum\solcnt<81\relax
    \global\multiply \difficultyctr 10\relax
  \fi
\typeout{************ Number of solutions = \the\solcnt}
\typeout{************ Difficulty rating = \the\difficultyctr}
}

\newcommand*{\checkkeepon}{%
  \ifnum\solcnt>80\relax
    \keeponfalse
  \fi
  \ifanychange\else
    \keeponfalse
  \fi}

%% Keep performing the simple reduction
\newcommand*{\keepreducingcells}{\bgroup
\commentary{Simple reductions}%
  \ifnum\difficultyctr<\tw@
    \global\difficultyctr\tw@
  \fi
  \changedtrue
  \loop
    \ifchanged
    \reduceallcells
    \checksimplereductions
  \repeat
\egroup}

\newcommand*{\checksimplereductions}{%
  \ifchanged\else
    \typesimplestatus
  \fi
  \ifnum\solcnt>80\relax%   solution found!
    \changedfalse
  \fi}

%%%%%%%%%%%%%%%%%%%%% reduce loners %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% reduce the loner digits, per row, column and box
\newcommand*{\reduceloners}{%
\commentary{reduceloners}%
  \global\lonerchangedfalse
  \ifnum\difficultyctr<4\relax
    \global\difficultyctr=4\relax
  \fi
  \ifnum\solcnt>80\else
    \bgroup
    \reducerowloners
    \iflonerchanged\else
      \reducecolloners
      \iflonerchanged\else
        \reduceboxloners
      \fi
    \fi
    \typelonestatus
    \egroup
  \fi}

%% Loop through the rows, reducing loners
\newcommand*{\reducerowloners}{%
  \sumctr\z@
  \s@dnrow\@ne
  \loop
    \ifnum\s@dnrow<10\relax
    \s@lcnta=\s@dnrow \advance\s@lcnta\m@ne
    \multiply\s@lcnta 9\relax \advance\s@lcnta\@ne
    \sumrowsets
    \ifnum\sumctr>\z@
      \getloner{\the\sumctr}{\s@dtempcntb}
      \ifnum\s@dtempcntb=\z@
      \else
        \reducelonerrowcell{\the\s@lcnta}{\the\s@dtempcntb}
        \iflonerchanged
          \advance\s@dnrow 10\relax
        \fi
      \fi
    \fi
    \advance\s@dnrow\@ne
  \repeat}

%% add the sets in the current row
\newcommand*{\sumrowsets}{%
  \bgroup
  \s@dncol=\s@lcnta
  \toprangectr=\s@dncol
  \advance\toprangectr 9\relax
  \global\sumctr\z@
  \loop
    \ifnum\s@dncol<\toprangectr
    \ifnum\useknt{s@lans\the\s@dncol}>\z@
      \global\advance\sumctr\useknt{s@lans\the\s@dncol}
    \fi
    \advance\s@dncol\@ne
  \repeat
  \egroup}

%% get the loner from a setsum
%% \getloner{setsum}{returnctr} returnes the (first) loner in a potential set,
%% or zero
\newcommand*{\getloner}[2]{\bgroup
  \ifnum #1>\z@
    \s@dtemploopcnta\@ne
    \loop
      \ifnum\s@dtemploopcnta<10\relax
      \numofnuminset{\the\s@dtemploopcnta}{#1}{\s@dtempcnta}
      \ifnum\s@dtempcnta=\@ne%         found a lone digit
        \s@dtempcnta=\s@dtemploopcnta
        \s@dtemploopcnta=100\relax
      \fi
      \advance\s@dtemploopcnta\@ne
    \repeat
    \ifnum\s@dtemploopcnta>99 \else \s@dtempcnta=\z@ \fi
    \global#2=\s@dtempcnta
  \else
    \s@dtempcnta=\z@
    \global#2=\s@dtempcnta
  \fi
\egroup}

%% \reducelonerowcell{startofrowcell}{digit}
%% given a row and a lone digit, find the cell containing the digit
%% and make the digit a solution of that cell.
\newcommand*{\reducelonerrowcell}[2]{\bgroup
  \s@dncol=#1
  \toprangectr=\s@dncol
  \advance\toprangectr 9\relax
  \ifnum #2<\@ne
    \advance\s@dncol 100\relax
  \fi
  \loop
    \ifnum\s@dncol<\toprangectr
    \numofnuminset{#2}{\the\useknt{s@lans\the\s@dncol}}{\lonecellctr}
    \ifnum\lonecellctr=\@ne%    this cell has the loner
      \lonecellctr=#2
      \global\useknt{s@lans\the\s@dncol}=-\lonecellctr
      \global\lonerchangedtrue
      \global\advance\solcnt\@ne
\commentary{\the\solcnt\space solved (#2 loner in row starting #1)}%
      \s@dncol=\toprangectr
    \fi
    \advance\s@dncol\@ne
  \repeat
\egroup}

%% Loop through the columns, reducing loners
\newcommand*{\reducecolloners}{\bgroup
  \sumctr\z@
  \s@dncol\@ne
  \loop
    \ifnum\s@dncol<10\relax
    \s@lcnta=\s@dncol
    \sumcolsets
    \ifnum\sumctr>\z@
      \getloner{\the\sumctr}{\s@dtempcntb}
      \ifnum\s@dtempcntb=\z@
      \else
        \reducelonercolcell{\the\s@lcnta}{\the\s@dtempcntb}
        \iflonerchanged
          \advance\s@dncol 10\relax
        \fi
      \fi
    \fi
    \advance\s@dncol\@ne
  \repeat
\egroup}

%% add the sets in the current column
\newcommand*{\sumcolsets}{\bgroup
  \s@dnrow=\s@lcnta
  \toprangectr=\s@dnrow
  \advance\toprangectr 73\relax
  \global\sumctr\z@
  \loop
    \ifnum\s@dnrow<\toprangectr
    \ifnum\useknt{s@lans\the\s@dnrow}>\z@
      \global\advance\sumctr\useknt{s@lans\the\s@dnrow}
    \fi
    \advance\s@dnrow 9\relax
  \repeat
\egroup}

%% \reducelonercolcell{startofcolcell}{digit}
%% given a col and a lone digit, find the cell containing the digit
%% and make the digit a solution of that cell.
\newcommand*{\reducelonercolcell}[2]{\bgroup
  \s@dnrow=#1
  \toprangectr=\s@dnrow
  \advance\toprangectr 73\relax
  \ifnum #2<\@ne
    \advance\s@dnrow 7300\relax
  \fi
  \loop
    \ifnum\s@dnrow<\toprangectr
    \numofnuminset{#2}{\the\useknt{s@lans\the\s@dnrow}}{\lonecellctr}
    \ifnum\lonecellctr=\@ne%    this cell has the loner
      \lonecellctr=#2
      \global\useknt{s@lans\the\s@dnrow}=-\lonecellctr
      \global\lonerchangedtrue
      \global\advance\solcnt\@ne
\commentary{\the\solcnt\space solved (#2 loner in column starting #1)}%
      \s@dnrow=\toprangectr
    \fi
    \advance\s@dnrow 9\relax
  \repeat
  \egroup}

%% Loop through the boxes, reducing loners
\newcommand*{\reduceboxloners}{\bgroup
  \sumctr\z@
  \boxctr\@ne
  \loop
    \ifnum\boxctr<10\relax
      \ifcase\boxctr
      \or \s@lcnta=\@ne
      \or \s@lcnta=4\relax
      \or \s@lcnta=7\relax
      \or \s@lcnta=28\relax
      \or \s@lcnta=31\relax
      \or \s@lcnta=34\relax
      \or \s@lcnta=55\relax
      \or \s@lcnta=58\relax
      \or \s@lcnta=61\relax
      \fi
      \sumboxsets
      \ifnum\sumctr>\z@
        \getloner{\the\sumctr}{\s@dtempcntb}
        \ifnum\s@dtempcntb=\z@
        \else
          \reducelonerboxcell{\the\s@lcnta}{\the\s@dtempcntb}
            \iflonerchanged
              \advance\boxctr 10\relax
            \fi
        \fi
      \fi
    \advance\boxctr\@ne
  \repeat
\egroup}

%% add the sets in the current box
\newcommand*{\sumboxsets}{\bgroup
  \s@dncol=\s@lcnta
  \toprangectr=\s@dncol
  \advance\toprangectr 3\relax
  \global\sumctr\z@
  \loop
    \ifnum\s@dncol<\toprangectr
    \s@dnrow=\s@dncol
    \ifnum\useknt{s@lans\the\s@dnrow}>\z@
      \global\advance\sumctr\useknt{s@lans\the\s@dnrow}
    \fi
    \advance\s@dnrow 9\relax
    \ifnum\useknt{s@lans\the\s@dnrow}>\z@
      \global\advance\sumctr\useknt{s@lans\the\s@dnrow}
    \fi
    \advance\s@dnrow 9\relax
    \ifnum\useknt{s@lans\the\s@dnrow}>\z@
      \global\advance\sumctr\useknt{s@lans\the\s@dnrow}
    \fi
    \advance\s@dncol\@ne
  \repeat
\egroup}

%% \reducelonerboxcell{startofboxcell}{digit}
%% given a box and a lone digit, find the cell containing the digit
%% and make the digit a solution of that cell.
\newcommand*{\reducelonerboxcell}[2]{\bgroup
  \s@dncol=\s@lcnta
  \toprangectr=\s@dncol
  \advance\toprangectr 3\relax
  \global\sumctr\z@
  \loop
    \ifnum\s@dncol<\toprangectr
    \s@dnrow=\s@dncol
    \numofnuminset{#2}{\the\useknt{s@lans\the\s@dnrow}}{\lonecellctr}
    \ifnum\lonecellctr=\@ne%    this cell has the loner
      \lonecellctr=#2
      \global\useknt{s@lans\the\s@dnrow}=-\lonecellctr
      \global\lonerchangedtrue
      \global\advance\solcnt\@ne
\commentary{\the\solcnt\space solved (#2 loner in box starting #1)}%
      \s@dncol=\toprangectr
    \fi
    \iflonerchanged\else
      \advance\s@dnrow 9\relax
      \numofnuminset{#2}{\the\useknt{s@lans\the\s@dnrow}}{\lonecellctr}
      \ifnum\lonecellctr=\@ne%    this cell has the loner
        \lonecellctr=#2
        \global\useknt{s@lans\the\s@dnrow}=-\lonecellctr
        \global\lonerchangedtrue
        \global\advance\solcnt\@ne
\commentary{\the\solcnt\space solved (#2 loner in box starting #1)}%
        \s@dncol=\toprangectr
      \fi
    \fi
    \iflonerchanged\else
      \advance\s@dnrow 9\relax
      \numofnuminset{#2}{\the\useknt{s@lans\the\s@dnrow}}{\lonecellctr}
      \ifnum\lonecellctr=\@ne%    this cell has the loner
        \lonecellctr=#2
        \global\useknt{s@lans\the\s@dnrow}=-\lonecellctr
        \global\lonerchangedtrue
        \global\advance\solcnt\@ne
\commentary{\the\solcnt\space solved (#2 loner in box starting #1)}%
        \s@dncol=\toprangectr
      \fi
    \fi
    \advance\s@dncol\@ne
  \repeat
\egroup}

%%%%%%%%%%%%%%%%%%%%% reduce pairs %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% reduce the pairs, per row, column and box
\newcommand*{\reducepairs}{\bgroup
\commentary{reducepairs}% **************************************}%
  \global\pairchangedfalse
  \ifnum\difficultyctr<8\relax
    \global\difficultyctr=8\relax
  \fi
  \ifnum\solcnt>80\else
    \reducerowpairs
    \ifpairchanged\else
      \reducecolpairs
      \ifpairchanged\else
        \reduceboxpairs
      \fi
    \fi
  \fi
\egroup}

%% Loop through the rows, reducing pairs
\newcommand*{\reducerowpairs}{%
  \sumctr\z@
  \s@dnrow\@ne
  \loop
    \ifnum\s@dnrow<10\relax
    \s@lcnta=\s@dnrow \advance\s@lcnta\m@ne
    \multiply\s@lcnta 9\relax \advance\s@lcnta\@ne
    \sumrowsets
    \ifnum\sumctr>\z@
      \reducearowpair{\the\s@lcnta}
      \ifpairchanged
        \advance\s@dnrow 10\relax
      \fi
    \fi
    \advance\s@dnrow\@ne
  \repeat}

%% reducearowpair{row}
\newcommand*{\reducearowpair}[1]{%
  \bgroup
  \s@dncol=#1\relax
  \toprangectr=\s@dncol
  \advance\toprangectr 9\relax
  \maxrangectr=\toprangectr
  \advance\maxrangectr\m@ne
  \global\sumctr\z@
  \loop
    \ifnum\s@dncol<\maxrangectr
    \asetctr=\useknt{s@lans\the\s@dncol}%
    \ifnum\asetctr>\z@
      \findrowpair
    \fi
    \advance\s@dncol\@ne
  \repeat
  \egroup}

\newcommand*{\findrowpair}{\bgroup
  \secondctr=\s@dncol
  \advance\secondctr\@ne
  \loop
    \ifnum\secondctr<\toprangectr
      \ifnum\asetctr=\useknt{s@lans\the\secondctr}
        \checksetforpair{\the\asetctr}
        \ifnum\numdigitsctr=\tw@
%% first row cell is \s@lcnta
%% first pair cell is \s@dncol, second pair cell is \secondctr
%% digits are \digitictr and \digitiictr
          \deleterowpairdigits
        \fi
      \fi
      \advance\secondctr\@ne
    \repeat
  \egroup}

%% \checksetforpair{set} returns with:
%%      \digitictr = first digit
%%      \digitiictr = second digit
%%      \numdigitsctr = number of digits (2 for a pair)
\newcommand*{\checksetforpair}[1]{\bgroup
  \s@dtemploopcnta\@ne
  \global\numdigitsctr\z@
  \global\digitictr\z@
  \global\digitiictr\z@
  \loop
    \ifnum\s@dtemploopcnta<10\relax
    \numofnuminset{\the\s@dtemploopcnta}{#1}{\s@dtempcnta}
    \ifnum\s@dtempcnta=\@ne
      \global\advance\numdigitsctr\@ne
      \ifcase\numdigitsctr
      \or \global\digitictr=\s@dtemploopcnta
      \or \global\digitiictr=\s@dtemploopcnta
      \else \advance\s@dtemploopcnta 10\relax
      \fi
    \fi
    \advance\s@dtemploopcnta\@ne
  \repeat
\egroup}

%% first row cell is \s@lcnta
%% first pair cell is \s@dncol, second pair cell is \secondctr
%% digits are \digitictr and \digitiictr
\newcommand*{\deleterowpairdigits}{\bgroup
  \global\pairchangedfalse
  \s@dtemploopcnta=\s@lcnta
  \toprangectr=\s@dtemploopcnta \advance\toprangectr 9\relax
  \loop
    \ifnum\s@dtemploopcnta<\toprangectr
    \ifnum\s@dtemploopcnta=\s@dncol
    \else
      \ifnum\s@dtemploopcnta=\secondctr
      \else
        \deletenumfromset{\the\digitictr}%
                        {\the\useknt{s@lans\the\s@dtemploopcnta}}{\s@dtempcnta}
        \ifsetchanged
          \global\useknt{s@lans\the\s@dtemploopcnta}=\s@dtempcnta
          \global\pairchangedtrue
        \fi
        \deletenumfromset{\the\digitiictr}%
                         {\the\useknt{s@lans\the\s@dtemploopcnta}}{\s@dtempcnta}
        \ifsetchanged
          \global\useknt{s@lans\the\s@dtemploopcnta}=\s@dtempcnta
          \global\pairchangedtrue
        \fi
      \fi
    \fi
  \advance\s@dtemploopcnta\@ne
  \repeat
\egroup}

%% Loop through the columns, reducing pairs
\newcommand*{\reducecolpairs}{%
  \sumctr\z@
  \s@dncol\@ne
  \loop
    \ifnum\s@dncol<10\relax
    \s@lcnta=\s@dncol
    \sumcolsets
    \ifnum\sumctr>\z@
      \reduceacolpair{\the\s@lcnta}
      \ifpairchanged
        \advance\s@dncol 10\relax
      \fi
    \fi
    \advance\s@dncol\@ne
  \repeat}

%% reduceacolpair{col}
\newcommand*{\reduceacolpair}[1]{\bgroup
  \s@dnrow=#1\relax
  \toprangectr=\s@dnrow
  \advance\toprangectr 73\relax
  \maxrangectr=\toprangectr
  \advance\maxrangectr -9\relax
  \global\sumctr\z@
  \loop
    \ifnum\s@dnrow<\maxrangectr
    \asetctr=\useknt{s@lans\the\s@dnrow}%
    \ifnum\asetctr>\z@
      \findcolpair
    \fi
    \advance\s@dnrow 9\relax
  \repeat
  \egroup}

\newcommand*{\findcolpair}{\bgroup
  \secondctr=\s@dnrow
  \advance\secondctr 9\relax
  \loop
    \ifnum\secondctr<\toprangectr
      \ifnum\asetctr=\useknt{s@lans\the\secondctr}
        \checksetforpair{\the\asetctr}
        \ifnum\numdigitsctr=\tw@
%% first row cell is \s@lcnta
%% first pair cell is \s@dnrow, second pair cell is \secondctr
%% digits are \digitictr and \digitiictr
          \deletecolpairdigits
        \fi
      \fi
      \advance\secondctr 9\relax
    \repeat
  \egroup}

%% first col cell is \s@lcnta
%% first pair cell is \s@dnrow, second pair cell is \secondctr
%% digits are \digitictr and \digitiictr
\newcommand*{\deletecolpairdigits}{\bgroup
  \global\pairchangedfalse
  \s@dtemploopcnta=\s@lcnta
  \toprangectr=\s@dtemploopcnta \advance\toprangectr 73\relax
  \loop
    \ifnum\s@dtemploopcnta<\toprangectr
    \ifnum\s@dtemploopcnta=\s@dnrow
    \else
      \ifnum\s@dtemploopcnta=\secondctr
      \else
        \deletenumfromset{\the\digitictr}%
                         {\the\useknt{s@lans\the\s@dtemploopcnta}}{\s@dtempcnta}
        \ifsetchanged
          \global\useknt{s@lans\the\s@dtemploopcnta}=\s@dtempcnta
          \global\pairchangedtrue
        \fi
        \deletenumfromset{\the\digitiictr}%
                         {\the\useknt{s@lans\the\s@dtemploopcnta}}{\s@dtempcnta}
        \ifsetchanged
          \global\useknt{s@lans\the\s@dtemploopcnta}=\s@dtempcnta
          \global\pairchangedtrue
        \fi
      \fi
    \fi
  \advance\s@dtemploopcnta 9\relax
  \repeat
\egroup}

%% Loop through the boxes, reducing pairs
\newcommand*{\reduceboxpairs}{\bgroup
  \sumctr\z@
  \boxctr\@ne
  \loop
    \ifnum\boxctr<10\relax
      \ifcase\boxctr
      \or \s@lcnta=\@ne
      \or \s@lcnta=4\relax
      \or \s@lcnta=7\relax
      \or \s@lcnta=28\relax
      \or \s@lcnta=31\relax
      \or \s@lcnta=34\relax
      \or \s@lcnta=55\relax
      \or \s@lcnta=58\relax
      \or \s@lcnta=61\relax
      \fi
      \sumboxsets
      \ifnum\sumctr>\z@
        \reduceaboxpair{\the\s@lcnta}
        \ifpairchanged
           \advance\boxctr 10\relax
        \fi
      \fi
      \advance\boxctr\@ne
  \repeat
\egroup}

%% \getnthboxcell{n}{firstcell}{returnctr}
\newcommand*{\getnthboxcell}[3]{\bgroup
  \s@dtempcnta=#2
  \ifcase#1
  \or
  \or \advance\s@dtempcnta 9\relax
  \or \advance\s@dtempcnta 18\relax
  \or \advance\s@dtempcnta \@ne
  \or \advance\s@dtempcnta 10\relax
  \or \advance\s@dtempcnta 19\relax
  \or \advance\s@dtempcnta \tw@
  \or \advance\s@dtempcnta 11\relax
  \or \advance\s@dtempcnta 20\relax
  \fi
  \global #3=\s@dtempcnta
\egroup}

%% \reduceaboxpair{startofboxcell}
\newcommand*{\reduceaboxpair}[1]{\bgroup
  \s@dtemploopcnta\@ne
  \toprangectr=\s@dtemploopcnta
  \advance\toprangectr 9\relax
  \maxrangectr=\toprangectr
  \advance\maxrangectr\m@ne
  \loop
    \ifnum\s@dtemploopcnta<\maxrangectr
    \getnthboxcell{\the\s@dtemploopcnta}{#1}{\s@dtempcnta}
    \asetctr=\useknt{s@lans\the\s@dtempcnta}
    \ifnum\asetctr>\z@
      \s@dnrow=\s@dtemploopcnta
      \findboxpair{#1}
    \fi
    \advance\s@dtemploopcnta\@ne
  \repeat
\egroup}

%% \findboxpair{startofboxcell}
\newcommand*{\findboxpair}[1]{%
  \bgroup
    \secondctr=\s@dtemploopcnta
    \advance\secondctr\@ne
    \loop
      \ifnum\secondctr<\toprangectr
      \getnthboxcell{\the\secondctr}{#1}{\s@dtempcntb}
      \ifnum\asetctr=\useknt{s@lans\the\s@dtempcntb}
        \checksetforpair{\the\asetctr}
        \ifnum\numdigitsctr=\tw@
%% first box cell is #1 (=\s@lcnta)
%% first pair cell is \s@dnrow, second pair cell is \secondctr
%% digits are \digitictr and \digitiictr
          \deleteboxpairdigits{#1}
        \fi
      \fi
      \advance\secondctr \@ne
    \repeat
  \egroup}

%% first box cell is #1
%% first pair cell is \s@dnrow, second pair cell is \secondctr
%% digits are \digitictr and \digitiictr
\newcommand*{\deleteboxpairdigits}[1]{\bgroup
  \global\pairchangedfalse
  \s@dtemploopcnta=\@ne
  \toprangectr=\s@dtemploopcnta \advance\toprangectr 9\relax
  \loop
    \ifnum\s@dtemploopcnta<\toprangectr
    \ifnum\s@dtemploopcnta=\s@dnrow
    \else
      \ifnum\s@dtemploopcnta=\secondctr
      \else
        \getnthboxcell{\the\s@dtemploopcnta}{#1}{\s@dtempcntb}
        \deletenumfromset{\the\digitictr}%
                         {\the\useknt{s@lans\the\s@dtempcntb}}{\s@dtempcnta}
        \ifsetchanged
          \global\useknt{s@lans\the\s@dtempcntb}=\s@dtempcnta
          \global\pairchangedtrue
        \fi
        \deletenumfromset{\the\digitiictr}%
                         {\the\useknt{s@lans\the\s@dtempcntb}}{\s@dtempcnta}
        \ifsetchanged
          \global\useknt{s@lans\the\s@dtempcntb}=\s@dtempcnta
          \global\pairchangedtrue
        \fi
      \fi
    \fi
  \advance\s@dtemploopcnta \@ne
  \repeat
\egroup}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% check solution %%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand*{\checksolution}{%
  \checkrows
  \checkcols
  \checkboxes}

\newcommand*{\checkrows}{%
  \sumctr\z@
  \s@dnrow\@ne
  \loop
    \ifnum\s@dnrow<10\relax
    \s@lcnta=\s@dnrow \advance\s@lcnta\m@ne
    \multiply\s@lcnta 9\relax \advance\s@lcnta\@ne
    \sumrowsets
    \ifnum\sumctr=\z@\else
\typeout{Row \the\s@dnrow\space is incorrect}%
      Row \the\s@dnrow\space is incorrect. \\
    \fi
    \advance\s@dnrow\@ne
  \repeat}

\newcommand*{\checkcols}{%
\bgroup
  \sumctr\z@
  \s@dncol\@ne
  \loop
    \ifnum\s@dncol<10\relax
    \s@lcnta=\s@dncol
    \sumcolsets
    \ifnum\sumctr=\z@\else
\typeout{Column \the\s@dncol\space is incorrect}%
      Column \the\s@dncol\space is incorrect. \\
    \fi
    \advance\s@dncol\@ne
  \repeat
\egroup}

\newcommand*{\checkboxes}{%
\bgroup
  \sumctr\z@
  \boxctr\@ne
  \loop
    \ifnum\boxctr<10\relax
\ifcase\boxctr
\or \s@lcnta=\@ne
\or \s@lcnta=4\relax
\or \s@lcnta=7\relax
\or \s@lcnta=28\relax
\or \s@lcnta=31\relax
\or \s@lcnta=34\relax
\or \s@lcnta=55\relax
\or \s@lcnta=58\relax
\or \s@lcnta=61\relax
\fi
    \sumboxsets
    \ifnum\sumctr=\z@\else
\typeout{Box \the\boxctr\space is incorrect}%
      Box \the\boxctr\space is incorrect. \\
    \fi
    \advance\boxctr\@ne
  \repeat
\egroup}

%% typeset the current status of the partial solution
\newcommand*{\typesimplestatusX}{%
\par\noindent\begin{minipage}{\linewidth}
\begin{center}
Simple reductions stopped (with \the\solcnt\space solutions)\\
\displaystatus
\end{center}
\end{minipage}}

%% typeset the current status after loner processing
\newcommand*{\typelonestatusX}{%
\par\noindent\begin{minipage}{\linewidth}
\begin{center}
Loners processed (with \the\solcnt\space solutions)\\
\displaystatus
\end{center}
\end{minipage}}

%% For curiosity as to how a solution is developing call the \showprogess
%% declaration (\hideprogess turns this off).
\newcommand*{\hideprogress}{%
  \let\typesimplestatus\relax
  \let\typelonestatus\relax}
\newcommand*{\showprogress}{%
  \let\typesimplestatus\typesimplestatusX
  \let\typelonestatus\typelonestatusX}
\hideprogress

%%%%%%%%%%%%%%%%%% write solution to a game file %%%%%%%%%%%%%%%

%% write out the solution to game file \sudsolnfile.
\newcommand*{\sudsolnfile}{sud.out}
\newcommand*{\writegame}{%
  \immediate\closeout\s@dwrite
  \immediate\openout\s@dwrite=\sudsolnfile
  \s@dnrow\@ne
  \loop
    \ifnum\s@dnrow<81\relax
    \gatherline{\the\s@dnrow}
    \immediate\write\s@dwrite{\sudaline}
    \advance\s@dnrow 9\relax
  \repeat
  \immediate\closeout\s@dwrite}

%% \gatherline{colstart}
%% collect all the characters for one line in a game file
\newcommand*{\gatherline}[1]{\bgroup
  \gdef\sudaline{}
  \s@dncol=#1\relax
  \toprangectr=\s@dncol
  \advance\toprangectr 9\relax
  \loop
    \ifnum\s@dncol<\toprangectr
    \s@dtempcnta=\useknt{s@lans\the\s@dncol}
    \ifnum\s@dtempcnta>\m@ne
      \g@addto@macro{\sudaline}{.}
    \else
      \s@dtempcnta=-\s@dtempcnta
      \ifcase\s@dtempcnta
      \or \g@addto@macro{\sudaline}{1}
      \or \g@addto@macro{\sudaline}{2}
      \or \g@addto@macro{\sudaline}{3}
      \or \g@addto@macro{\sudaline}{4}
      \or \g@addto@macro{\sudaline}{5}
      \or \g@addto@macro{\sudaline}{6}
      \or \g@addto@macro{\sudaline}{7}
      \or \g@addto@macro{\sudaline}{8}
      \or \g@addto@macro{\sudaline}{9}
      \else \g@addto@macro{\sudaline}{.}
      \fi
    \fi
    \advance\s@dncol\@ne
  \repeat
\egroup}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% THE END GOAL %%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%% \sudoksolve{<file>} %%%%%%%%%%%%%%%%%%%%%%

%% Read in and typeset the problem, solve it, and typeset the answer
\newcommand{\sudokusolve}[1]{%
  \begin{center}
  \sudoku{#1}%
  \end{center}
  \getproblem{#1}%
  \reduceallcells
  \keepreducing
  \writegame
  \noindent\begin{minipage}{\linewidth}
  THE ANSWER
  \begin{center}
  \cluefont\normalsize
  \cellsize{1.5\baselineskip}
  \sudoku{\sudsolnfile}
  \end{center}
  \end{minipage}}

\endinput
%%
%% End of file `solvesudoku.sty'.
