From 4cdec44e9893db7879eb9f2f34cfcbe52072abd0 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sun, 20 Aug 2006 00:06:14 +0000 Subject: new (latex games) package sudokubundle 1.0 (17feb06) git-svn-id: svn://tug.org/texlive/trunk@1992 c570f23f-e606-0410-a88d-b1316a301751 --- .../tex/latex/sudokubundle/createsudoku.sty | 299 ++++ .../tex/latex/sudokubundle/printsudoku.sty | 151 +++ .../tex/latex/sudokubundle/solvesudoku.sty | 1428 ++++++++++++++++++++ 3 files changed, 1878 insertions(+) create mode 100644 Master/texmf-dist/tex/latex/sudokubundle/createsudoku.sty create mode 100644 Master/texmf-dist/tex/latex/sudokubundle/printsudoku.sty create mode 100644 Master/texmf-dist/tex/latex/sudokubundle/solvesudoku.sty (limited to 'Master/texmf-dist/tex') diff --git a/Master/texmf-dist/tex/latex/sudokubundle/createsudoku.sty b/Master/texmf-dist/tex/latex/sudokubundle/createsudoku.sty new file mode 100644 index 00000000000..faa200f3e44 --- /dev/null +++ b/Master/texmf-dist/tex/latex/sudokubundle/createsudoku.sty @@ -0,0 +1,299 @@ +%% +%% This is file `createsudoku.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% sudokubundle.dtx (with options: `create') +%% +%% ----------------------------------------------------------------- +%% 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{createsudoku}[2006/02/16 v1.0 create sudoku puzzles] +\input{random} +\RequirePackage{solvesudoku} + +\let\oldcommentary\commentary +\let\commentary\@gobble +\newcommand*{\gencommentary}[1]{\typeout{#1}} + +\newcommand*{\genfile}{gensud.sud} +\newcommand*{\prevfile}{genprev.sdx} +\newcommand*{\currfile}{gencurr.sdx} + +\randomi\m@ne +\newcommand*{\setsudrandom}[1]{% + \randomi=#1\relax + \ifnum\randomi<\@ne\else + \nextrandom \nextrandom \nextrandom + \typeout{random initialised to #1}% + \fi} + +\newcommand*{\generategrid}[1][\@empty]{% + \ifx\@empty #1 + \writestartgrid + \getproblem{\prevfile} + \else + \getproblem{#1} + \fi + \swaps + \elimclues + \printsudresults} +\newcommand*{\printsudresults}{% + \sudokusolve{\genfile}% + } + +%% the starting data +\newcommand*{\writestartgrid}{% + \immediate\closeout\s@dwrite + \immediate\openout\s@dwrite=\prevfile + \immediate\write\s@dwrite{123456789} + \immediate\write\s@dwrite{456789123} + \immediate\write\s@dwrite{789123456} + \immediate\write\s@dwrite{234567891} + \immediate\write\s@dwrite{567891234} + \immediate\write\s@dwrite{891234567} + \immediate\write\s@dwrite{345678912} + \immediate\write\s@dwrite{678912345} + \immediate\write\s@dwrite{912345678} + \immediate\closeout\s@dwrite} + +\newcommand*{\swaps}{\bgroup + \setrannum{\maxrangectr}{36}{48}% +\gencommentary{number of swaps (36--48) = maxrangectr = \the\maxrangectr} + \s@dtemploopcnta\@ne + \loop + \ifnum\s@dtemploopcnta<\maxrangectr + \setrannum{\s@dtempcntb}{1}{18}% +%%\typeout{\space\space\space swap no \the\s@dtemploopcnta\space is \the\s@dtempcntb} + \ifcase\s@dtempcntb + \or \swapcolpair{1}{2}% + \or \swapcolpair{1}{3}% + \or \swapcolpair{2}{3}% + \or \swapcolpair{4}{5}% + \or \swapcolpair{4}{6}% + \or \swapcolpair{5}{6}% + \or \swapcolpair{7}{8}% + \or \swapcolpair{7}{9}% + \or \swapcolpair{8}{9}% + \or \swaprowpair{1}{10}% + \or \swaprowpair{1}{19}% + \or \swaprowpair{10}{19}% + \or \swaprowpair{28}{37}% + \or \swaprowpair{28}{46}% + \or \swaprowpair{37}{46}% + \or \swaprowpair{55}{64}% + \or \swaprowpair{55}{73}% + \or \swaprowpair{64}{73}% + \fi + \advance\s@dtemploopcnta\@ne + \repeat +\egroup} + +%% swap the data in rows starting at #1, and #2 +\newcommand*{\swaprowpair}[2]{\bgroup + \s@dncol=#1\relax + \s@dcolpos=#2\relax + \s@dtemploopcnta\@ne + \maxrangectr=10\relax + \loop + \ifnum\s@dtemploopcnta<\maxrangectr + \s@dtempcnta=\useknt{s@lans\the\s@dncol}% + \global\useknt{s@lans\the\s@dncol}=\useknt{s@lans\the\s@dcolpos}% + \global\useknt{s@lans\the\s@dcolpos}=\s@dtempcnta + \advance\s@dncol\@ne + \advance\s@dcolpos\@ne + \advance\s@dtemploopcnta\@ne + \repeat +\egroup} + +%% swap the data in cols starting #1 and #2 +\newcommand*{\swapcolpair}[2]{\bgroup + \s@dnrow=#1\relax + \s@drowpos=#2\relax + \s@dtemploopcnta\@ne + \maxrangectr=10\relax + \loop + \ifnum\s@dtemploopcnta<\maxrangectr + \s@dtempcnta=\useknt{s@lans\the\s@dnrow}% + \global\useknt{s@lans\the\s@dnrow}=\useknt{s@lans\the\s@drowpos}% + \global\useknt{s@lans\the\s@drowpos}=\s@dtempcnta + \advance\s@dnrow 9\relax + \advance\s@drowpos 9\relax + \advance\s@dtemploopcnta\@ne + \repeat +\egroup} + +\newcommand*{\elimclues}{\bgroup + \initialelimination + \writestate{\prevfile}% + \writestate{\currfile}% + \elimcluesonebyone + \getproblem{\prevfile} + \writestate{\genfile} +\egroup} + +\newcommand*{\elimseventeen}{\bgroup + \s@dtemploopcnta\@ne + \maxrangectr 18\relax + \loop + \ifnum\s@dtemploopcnta<\maxrangectr + \setrannum{\s@dtempcnta}{1}{81} + \global\useknt{s@lans\the\s@dtempcnta}=111111111\relax + \advance\s@dtemploopcnta\@ne + \repeat +\egroup} + +%% eliminates all clues in column 5 and row 5 +\newcommand*{\elimcross}{\bgroup + \s@dtemploopcnta 5\relax + \loop + \ifnum\s@dtemploopcnta<78\relax% 78 = 5 + 73 + \global\useknt{s@lans\the\s@dtemploopcnta}=111111111\relax + \advance\s@dtemploopcnta 9\relax + \repeat + \s@dtemploopcnta 37\relax + \loop + \ifnum\s@dtemploopcnta<46\relax% 46 = 37 + 9 + \global\useknt{s@lans\the\s@dtemploopcnta}=111111111\relax + \advance\s@dtemploopcnta \@ne + \repeat +\egroup} + +\newcommand*{\elimnum}[1]{\bgroup + \s@dtemploopcnta\@ne + \loop + \ifnum\s@dtemploopcnta<82\relax + \ifnum\useknt{s@lans\the\s@dtemploopcnta}=-#1\relax + \global\useknt{s@lans\the\s@dtemploopcnta}=111111111\relax + \fi + \advance\s@dtemploopcnta \@ne + \repeat +\egroup} + +\newcommand*{\elimcrossandnines}{\bgroup + \elimcross + \s@dtemploopcnta\@ne + \loop + \ifnum\s@dtemploopcnta<82\relax + \ifnum\useknt{s@lans\the\s@dtemploopcnta}=-9\relax + \global\useknt{s@lans\the\s@dtemploopcnta}=111111111\relax + \fi + \advance\s@dtemploopcnta \@ne + \repeat +\egroup} + +\newcommand*{\elimex}{\bgroup + \s@dtemploopcnta\@ne + \loop + \ifnum\s@dtemploopcnta<82\relax + \global\useknt{s@lans\the\s@dtemploopcnta}=111111111\relax + \advance\s@dtemploopcnta 10\relax + \repeat + \s@dtemploopcnta=9\relax + \loop + \ifnum\s@dtemploopcnta<81\relax + \global\useknt{s@lans\the\s@dtemploopcnta}=111111111\relax + \advance\s@dtemploopcnta 8\relax + \repeat +\egroup} + +\newcommand*{\elimcrossandex}{\bgroup + \elimcross + \elimex +\egroup} + +\newcommand*{\elimcrossandexandnines}{\bgroup + \elimcross + \elimex + \elimnum{9} +\egroup} + +\let\initialelimination\elimseventeen +\let\initialelimination\elimcross +\let\initialelimination\elimcrossandnines +\let\initialelimination\elimcrossandex +\let\initialelimination\elimcrossandexandnines + +\newcount\toomanyloops +\newcommand*{\elimcluesonebyone}{\bgroup +%%%\typeout{***elimcluesonebyone} +\toomanyloops\z@ + \s@dtempcntb=81\relax + \loop + \ifnum\s@dtempcntb>80\relax +\advance\toomanyloops\@ne + \getproblem{\currfile} + \trysolution + \ifnum\solcnt=81\relax % can delete another clue + \getproblem{\currfile} + \writestate{\prevfile} + \deleteaclue + \writestate{\currfile}% + \s@dtempcntb=81\relax + \else % done + \typeout{Solver failed, solcnt = \the\solcnt} + \s@dtempcntb=\@ne + \fi + \ifnum\toomanyloops>80\relax + \typeout{Too much looping} + \s@dtempcntb=\@ne + \fi + \repeat +\egroup} + +\newif\ifacluenotdeleted +\newcommand*{\deleteaclue}{\bgroup + \acluenotdeletedtrue + \loop + \ifacluenotdeleted + \setrannum{\s@dtempcnta}{1}{81}% + \ifnum\useknt{s@lans\the\s@dtempcnta}<\z@% found a clue + \gencommentary{Deleting clue for cell \the\s@dtempcnta}% + \global\useknt{s@lans\the\s@dtempcnta}=111111111\relax + \acluenotdeletedfalse + \fi + \repeat +\egroup} + +\newcommand*{\trysolution}{\bgroup + \reduceallcells + \keepreducing +\egroup} + +%% \writestate{} +\newcommand*{\writestate}[1]{\bgroup + \immediate\closeout\s@dwrite + \immediate\openout\s@dwrite=#1 + \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 +\egroup} + +\endinput +%% +%% End of file `createsudoku.sty'. diff --git a/Master/texmf-dist/tex/latex/sudokubundle/printsudoku.sty b/Master/texmf-dist/tex/latex/sudokubundle/printsudoku.sty new file mode 100644 index 00000000000..09dae133f6d --- /dev/null +++ b/Master/texmf-dist/tex/latex/sudokubundle/printsudoku.sty @@ -0,0 +1,151 @@ +%% +%% This is file `printsudoku.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% sudokubundle.dtx (with options: `print') +%% +%% ----------------------------------------------------------------- +%% 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{printsudoku}[2006/02/16 v1.0 typeset sudoku puzzles] + +\newread\s@dread +\newwrite\s@dwrite + +%%%% open game file +\newcommand*{\reads@dgame}[1]{% + \closein\s@dread + \openin\s@dread=#1} + +%%% set size of a game cell +\newlength\halfs@dcell +\newcommand*{\cellsize}[1]{% + \halfs@dcell=#1\relax + \halfs@dcell=0.5\halfs@dcell} +\cellsize{2.5\baselineskip} +%% set font for the numbers +\newcommand*{\cluefont}[1]{\def\s@dfont{#1}} +\cluefont{\Huge} + +%% counts for looping and cell positions +\newcount\s@dncol +\newcount\s@dnrow +\newcount\s@dcolpos +\newcount\s@drowpos + +%% insert the clues into the game array +\newcommand*{\adds@dclues}{% + \firsts@dcluetrue + \s@dnrow\@ne + \loop + \ifnum\s@dnrow<10\relax + \read\s@dread to \s@dline + \firsts@dcluetrue + \s@drowpos=\s@dnrow + \multiply\s@drowpos\tw@ + \advance\s@drowpos\m@ne + \s@dncol\@ne + \dos@dcols + \advance\s@dnrow\@ne + \repeat + \closein\s@dread} + +%% insert a row of clues +\newcommand*{\dos@dcols}{% +\bgroup + \loop + \ifnum\s@dncol<10\relax + \s@dcolpos=\s@dncol + \multiply\s@dcolpos\tw@ + \advance\s@dcolpos\m@ne + \put(\s@dcolpos,-\s@drowpos){\makebox(0,0){\s@dfont\gets@dclue}}% + \advance\s@dncol\@ne + \repeat +\egroup} + +%% get the next character in a string +\def\gettwo#1#2\nowt{% + \gdef\istchar{#1}\gdef\restchars{#2}} +\def\splitoff#1{\gettwo#1\nowt} +%% a full stop (period) +\gdef\s@dfstop{.} + +%% get the next clue in the line +\newif\iffirsts@dclue +\firsts@dcluetrue +\newcommand*{\gets@dclue}{% + \iffirsts@dclue + \expandafter\splitoff\expandafter{\s@dline}% + \global\firsts@dcluefalse + \else + \expandafter\splitoff\expandafter{\restchars}% + \fi + \ifx\s@dfstop\istchar + \else + \istchar + \fi} + +%% typeset the grid, then add the clues +\newcommand*{\s@dgame}{% + \setlength\unitlength\halfs@dcell + \begin{picture}(18,18)(0,-18) + \thinlines + \multiput(0,0)(2,0){10}{\line(0,-1){18}} + \multiput(0,0)(0,-2){10}{\line(1,0){18}} + \thicklines \linethickness{1pt} + \multiput(0,0)(6,0){4}{\line(0,-1){18}} + \multiput(0,0)(0,-6){4}{\line(1,0){18}} + \adds@dclues + \end{picture}} + +%% the whole shebang, where #1 is the name of the game file +\newcommand*{\sudoku}[1]{% + \reads@dgame{#1}% + \s@dgame} + +\newcommand*{\puzzlefile}{puzz.sud} +\newcommand*{\writepuzzle}[9]{% + \immediate\closeout\s@dwrite + \immediate\openout\s@dwrite=\puzzlefile + \immediate\write\s@dwrite{#1}% + \immediate\write\s@dwrite{#2}% + \immediate\write\s@dwrite{#3}% + \immediate\write\s@dwrite{#4}% + \immediate\write\s@dwrite{#5}% + \immediate\write\s@dwrite{#6}% + \immediate\write\s@dwrite{#7}% + \immediate\write\s@dwrite{#8}% + \immediate\write\s@dwrite{#9}% + \writes@dpuzzend} +\newcommand*{\writes@dpuzzend}[1][\@empty]{ + \ifx\@empty #1\else + \immediate\write\s@dwrite{ }% + \immediate\write\s@dwrite{#1}% + \fi + \immediate\closeout\s@dwrite} +\newcommand*{\sudpuzznewline}{^^J} + +\endinput +%% +%% End of file `printsudoku.sty'. diff --git a/Master/texmf-dist/tex/latex/sudokubundle/solvesudoku.sty b/Master/texmf-dist/tex/latex/sudokubundle/solvesudoku.sty new file mode 100644 index 00000000000..f349442e178 --- /dev/null +++ b/Master/texmf-dist/tex/latex/sudokubundle/solvesudoku.sty @@ -0,0 +1,1428 @@ +%% +%% 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{} %%%%%%%%%%%%%%%%%%%%%% + +%% 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'. -- cgit v1.2.3