<HTML>
<HEAD>
<TITLE>Sudoku Solver</TITLE>
</HEAD>

<BODY TEXT="#000000" BGCOLOR="#F8F8FC">

<H1>Sudoku Solver</H1>

<H3><FONT COLOR="#FF0000">NEU: Auflistung aller Einzelschritte inklusive genauer Erkl&auml;rungen und Punkte-Bewertung - und mit Goldenen Ketten; jetzt auch mit Eindeutigkeitstest</FONT></H3>

<?
// Einfachste Programmierloesung mit einem einzeiligen (alle Zeilen nebeneinander) Array (mit Index 0 - 80),
//   wobei ueber die Funktion row/col/box zu einem gegebenen Index alle (jeweils 9) zu einer
//   Zeile, Spalte oder Box gehoerenden Indizes berechnet und als Array zurueckgegeben werden.

// Also: Berechne aus dem Index (0 - 80) eines Feldes die Indizes der zugehoerigen Zeile, Spalte, Box.
// Dabei kann der Eingabe-Index irgendein Element des Feldes sein! D.h. man findet zu einem
//   beliebigen Element damit alle Indizes einer Zeile, Spalte und/oder Box, in der das Element steht.
// Die Funktionen row_number, col_number, box_number_x sind nur fuer besser lesbare Ausgabetexte.

function row($index) {
    
// Pattern: r*9 + i
    
$r floor($index/9);
    for (
$i 0$i 9$i++) $k[$i] = $r*$i;
    return 
$k;
}
function 
row_number($index) {
    
$r floor($index/9);
    return 
$r;
}

function 
col($index) {
    
// Pattern: s + i*9
    
$c fmod($index,9);
    for (
$i 0$i 9$i++) $l[$i] = $c $i*9;
    return 
$l;
}
function 
col_number($index) {
    
$c fmod($index,9);
    return 
$c;
}

function 
box($index) {
    
// Pattern: (u*3 + t*27) + (i*9 + j)
    
$r floor($index/9);
    
$c fmod($index9);  // $index - $r*9;
    
$t floor($r/3);
    
$u floor($c/3);
    
$v $t*27 $u*3;
    
$w 0;
    for (
$i 0$i 3$i++) {
        for (
$j 0$j 3$j++) {
            
$m[$w] = $v $i*$j;
            
$w++;
        }
    }
    return 
$m;
}
function 
box_number_r($index) {
    
$r floor($index/9);
    
$t floor($r/3);    // Geht natuerlich auch in einem Schritt
    
return $t;
}
function 
box_number_c($index) {
    
$c fmod($index9);
    
$u floor($c/3);
    return 
$u;
}

// Aus Symmetriegruenden hier beibehalten:
// Fuer Farbsudokus
function frb($index) {
    
// Pattern: (r*9 + c) + (a*3 + b*27)
    
$b floor($index/27);
    
$rest fmod($index27); // $index - $b*27;
    
$r floor($rest/9);
    
$rest fmod($rest9); // $rest - $r*9;
    
$a floor($rest/3);
    
$rest fmod($rest3); // $rest - $a*3;
    
$c floor($rest/1);
    
$v $r*$c;
    
$x 0;
    for (
$b 0$b 3$b++) {
        for (
$a 0$a 3$a++) {
            
$n[$x] = $v $a*$b*27;
            
$x++;
        }
    }
    return 
$n;
}

function 
show_row($r) {
    echo 
"<TR>\n";
    for (
$k 0$k 9$k++) {
        
$value $r[$k];
        if (
count($r) == 9) {
            if (
$r[$k] === 0) echo "<TD><INPUT TYPE=TEXT VALUE=\"\" SIZE=1 MAXLENGTH=1></TD>\n";
            else echo 
"<TD><B>$r[$k]</B></TD>\n";
        }
        elseif (
count($r) == 18) {
            
$rest $r[$k+9];
            if (
$rest == ""$rest "&nbsp;";
            if (
$r[$k] === 0) echo "<TD><INPUT TYPE=TEXT VALUE=\"\" SIZE=1 MAXLENGTH=1><BR>$rest</TD>\n";
            else echo 
"<TD><B>$r[$k]</B><BR>$rest</TD>\n";
        }
        if (
$k == || $k == 5) echo "<TD>|<BR>|</TD>\n";
    }
    echo 
"</TR>\n";
}

function 
erklaerung() {
    global 
$farbe_gruen$farbe_rot$farbe_blau$farbe_braun$farbe_lila$farbe_rotgelb;
    
    echo 
"<H4>Prinzipen zur L&ouml;sung von Sudokus</H4>\n";
  
    echo 
"Sudoku-Grundregel: Es sollen in jeder Zeile, in jeder Spalte und in jeder Box (3x3-K&auml;stchen) alle Zahlen von 1 bis 9 genau einmal vorkommen. Die Zeilen und Spalten werden hier von oben links an mit 1 bis 9 durchnummeriert, die Boxen werden mit OL (oben links), OM (oben Mitte), OR (oben rechts), ML (Mitte links), MM (Mitte Mitte), ..., bis UR (unten rechts) bezeichnet.\n";
  
    echo 
"<P>Dieses Programm benutzt 5 L&ouml;sungsverfahren mit verschiedener Punkte-Gewichtung, wobei f&uuml;r die Ausd&uuml;nnung 5 verschiedene Analysemethoden (ebenfalls mit unterschiedlichen Punkten gewichtet) programmiert wurden.\n";
    echo 
"<BR>Dabei wird nach einem Treffer immer wieder bei der einfachsten Methode begonnen, und zus&auml;tzlich in der Reihenfolge: Suche immer erst in Zeilen - dadurch sind diese F&auml;lle immer am h&auml;ufigsten -, dann in Spalten, zuletzt in Boxen.\n";
  
    echo 
"<P>Bei der Bewertung wird davon ausgegangen, dass zuerst versucht wird, das Sudoku ohne Anschreiben der Reste (Kandidaten) zu l&ouml;sen. Dabei kommen die Methoden A, B und C zum Einsatz. Kommt man damit nicht weiter, muss man f&uuml;r jede Zelle alle Zahlen aufschreiben, die daf&uuml;r in Frage kommen: die Kandidaten, die hier als Ganzes oft Rest genannt und auch der Einfachheit halber als eine mehrstellige Zahl (ohne Komma oder andere Trennzeichen) geschrieben werden. Danach versucht man, diese Reste so lange auszud&uuml;nnen, also zu verk&uuml;rzen, bis man zu einer eindeutigen L&ouml;sung f&uuml;r eine Zelle kommt (Methoden D und E). Das Ausd&uuml;nnen (Kandidaten-Reduzierung) wird hier mit den wichtigsten 5 Methoden versucht, die weiter unten erkl&auml;rt werden.\n";
  
    echo 
"<P>Trial- and Error-Verfahren werden nicht benutzt, sondern nur logisch nachvollziehbare Methoden - dieses Programm soll nicht ein Sudoku l&ouml;sen, sondern alle L&ouml;sungsschritte aufzeigen. Ein \"richtiges\" Sudoku sollte immer ohne \"zuf&auml;lligen\" Versuch und Irrtum und auf jeden Fall eindeutig gel&ouml;st werden k&ouml;nnen.\n";
  
    echo 
"<H4>Programm-Neuigkeiten</H4>\n";
    echo 
"<UL>\n";
    
    echo 
"<LI>Die bei <A HREF=\"http://sourceforge.net/projects/php-sudoku/\">http://sourceforge.net/projects/php-sudoku/</A> gefundenen 1 Million Sudokus (Dank an Michael Jentsch) wurden durchgerechnet. Sie sind aber etwas einfacher als die hier bisher gesammelten mehr als 22000 Sudokus, denn 965351 Sudokus konnte ohne Ausd&uuml;nnung gerechnet werden, 30420 Sudokus (3 %) konnten nur mit Ausd&uuml;nnung gel&ouml;st werden, und nur 4229 (0.4 %) Sudokus konnten mit diesem Programm nicht gel&ouml;st werden, hatten aber eine eindeutige L&ouml;sung, die sich durch Trial&Error aber im Allgemeinen auch sehr einfach finden lie&szlig;. Interessant wieder: X-Wings waren 4483 dabei, aber Goldene Ketten 47581, fast 11 Mal so viel (August 2010).</LI><P>\n";

    echo 
"<LI>Die jeweils neu gefundene Zahl wird mit spitzen Klammern, also z.B. &gt;7&lt; markiert (Juli 2010).</LI><P>\n";
  
    echo 
"<LI>Die Beispiele wurden in ihrem Aufbau ver&auml;ndert und auf eine extra Webseite gebracht, damit die eigentliche Seite nicht zu lang ist (Juni 2010).</LI><P>\n";
    
    echo 
"<LI>Jetzt gibt es die M&ouml;glichkeit, ein Sudoku, das mit den hier programmierten Methoden nicht gel&ouml;st werden kann, auf eindeutige L&ouml;sbarkeit testen zu lassen. Von 3400 untersuchten hier nicht l&ouml;sbaren Sudokus waren etwa 630 eindeutig l&ouml;sbar, &uuml;ber 2500 hatten mehr als eine L&ouml;sung - mit bis zu 52000 verschiedenen L&ouml;sungen - und etwa 230 waren prinzipiell nicht l&ouml;sbar (Mai/Juni 2010).</LI><P>\n";
    
    echo 
"<LI>Die Punkte-Bewertung wurde ge&auml;ndert, insbesondere wurden die A-Methoden getrennt, da man eine fehlende Zahl in Boxen einfacher (1 Punkt) sieht als in Zeilen oder Spalten (2 Punkte); und eine jeweils 9. fehlende Zahl wird gar nicht bewertet. Au&szlig;erdem werden die Felder gez&auml;hlt und mit je 1 Punkt bewertet, in denen zur Ausd&uuml;nnung Reste eingetragen werden m&uuml;ssen (April/Mai 2010).</LI><P>\n";
  
    echo 
"<LI>Jetzt wurden die Erkl&auml;rungen und Beispiele zum Verst&auml;ndnis der L&ouml;sungsstrategien vollkommen &uuml;berarbeitet und dabei auch Fehler behoben (Sorry!). Vielleicht kann man das Ganze nun besser verstehen... (M&auml;rz 2010).</LI><P>\n";
  
    echo 
"<LI>Es wurden auch schon &uuml;ber 200 Stunden f&uuml;r die Analyse der &uuml;ber 20000 Beispiele aufgewendet, z.B. f&uuml;r die verschiedenen Beispiel-Listen (h&ouml;chste Punktzahl, l&auml;ngste Goldene Kette, l&ouml;sbar nur durch Quadrupel, usw.), - insbesondere ein paar Dutzend Prozeduren geschrieben, um das Ganze einigerma&szlig;en automatisch zu erzeugen, da es immer wieder aktualisiert wird. Auch die beiden Reduzierungsl&auml;ufe kosteten einiges an Zeit... (Februar 2010).</LI><P>\n";
  
    echo 
"<LI>Endlich wurde auch die Ausd&uuml;nn-Methode X-Wing programmiert (in 5 Stunden von nun insgesamt etwa 300 Stunden Programmierarbeit). Leider erbrachte das aber auch nur knapp 1% mehr L&ouml;sungen (gegen&uuml;ber 15% bei der Goldenen Kette!)... Aber immerhin hat die X-Wing-Methode den Vorteil, auch bei Zellen mit mehr als 2 Kandidaten zu funktionieren (gegen&uuml;ber der Goldenen Ketten) - weswegen die Programmierung doch sinnvoll ist (Januar 2010).</LI><P>\n";
  
    echo 
"<LI>Dem entsprechend wurde auch die Reihenfolge der Ausd&uuml;nn-Methoden umgestellt: Zuerst kommen nun die einfachen Zeilen-/Spalten-/Box-Test-Methoden, danach erst die N-Tupel, dann X-Wing und am Ende die Goldenen Ketten (Januar 2010).</LI><P>\n";

    echo 
"<LI>Es wurde die Goldene Kette in einer zweiten Version programmiert: K&uuml;rzere Kette werden zuerst gefunden (Maximall&auml;nge 14 - gegen&uuml;ber vorher 23). Erstaunlichstes Ergebnis &uuml;berhaupt aber war, dass durch die Programmierung der Goldenen Ketten 15% mehr L&ouml;sungen gefunden werden konnten als voher - und zwar auch noch fast genau so viele wie durch die Methode der 2-Tupel (Doppel) gefunden werden! Das Verfahren ist damit eine sehr wichtige Methode, aber auch aufw&auml;ndiger: Es wurden schon Sudokus mit einer Rechenzeit von &uuml;ber 20 Sekunden (auf dem aktuellen Webserver) gel&ouml;st (bei der ersten Version aber wesentlich l&auml;nger) - 30 Sekunden stehen bei Web-Anwendungen im Allgemeinen nur zur Verf&uuml;gung (Dezember 2009; erste Version mit Rekursion: November 2009).</LI><P>\n";

    echo 
"<LI>Die Programmierung der N-Tupel wurde verbessert, so dass nun auch N-Tupel gefunden werden, deren einzelne Mitglieder alle aus weniger als N Zahlen bestehen. Die gew&auml;hlte Methode erkennt nun etwa 99.9% dieser F&auml;lle - eine nochmals erweiterte Programmierung brachte nur ein Beispiel aus 10000 Sudokus, kostet aber 15 % mehr an Laufzeit und wird deswegen weggelassen (die Programmteile sind auskommentiert und k&ouml;nnten auf dem eigenen Rechner aktiviert werden)... Versteckte N-Tupel m&uuml;ssen nicht extra programmiert werden, da sie immer mit direkten N-Tupel korrespondieren (Oktober 2009).</LI><P>\n";
  
    echo 
"<LI>Es fehlt die Programmierung von weiteren Ausd&uuml;nn-Methoden wie z.B.: Swordfish (Erweiterung von X-Wing), und Colouring und Multicolouring, die aber nicht so viel zus&auml;tzliche Sudokus l&ouml;sen werden k&ouml;nnen wie die bisherigen Methoden (auch X-Wing hatte ja nicht so viel gebracht...).</LI><P>\n";
  
    echo 
"</UL>\n";
  
    echo 
"<H4>F&uuml;nf Sudoku-L&ouml;sungsmethoden (A bis E)</H4>\n";
  
    echo 
"<OL TYPE=\"A\">\n";
    
    echo 
"<LI>Einfachste Methode (Wert: 1 Punkt innerhalb Boxen, 2 Punkte innerhalb Zeilen/Spalten, 0 Punkte bei der 9. fehlenden Zahl; Farbmarkierung: <FONT COLOR=$farbe_gruen>Gr&uuml;n</FONT>): Direkte Dreier-Methode oder eindeutige Stelle: Bestimme die fehlende dritte Zahl in drei zusammen liegenden (nebeneinander oder untereinander) Boxen. D.h.: Findet man in zwei von drei zusammen liegenden Boxen eine bestimmte Zahl, sucht man in der dritten Box nach einem eindeutigen Ort, an dem diese Zahl stehen kann. In vielen F&auml;llen ist es auch einfach die einzige Stelle, an der eine bestimmte Zahl nur stehen kann, insbesondere beim Durchsuchen von Zeilen und Spalten.\n";
    echo 
"<BR>Bemerkung: In knapp 95 % aller L&ouml;sungsschritte findet man eine Zahl (und den dazugeh&ouml;renden Ort) mit dieser Methode, davon 90 % mit der Suche innerhalb von Boxen!</LI>\n";
  
    echo 
"<P>Einfacher Fall:\n";
    echo 
"<BR>In der dritten Box (OR) kann die Zahl 7 nur in der dritten Zeile sein; damit bleibt die letzte Spalte als einzig m&ouml;glicher Ort &uuml;brig (mit kleinem x markiert).\n";
    echo 
"<BR>PS: Der &Uuml;bersichtlichkeit wegen wurden viele Felder nicht ausgef&uuml;llt, da deren Inhalt ohne Bedeutung ist; ebenso fehlen im Allgemeinen die letzten Zeilen der Beispiel-Sudokus.\n";

    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(000070000));
    
show_row(array(700000000));
    
show_row(array(00000145"<INPUT TYPE=TEXT VALUE=\"x\" SIZE=1 MAXLENGTH=1>"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
    
    echo 
"<P>Komplexerer Fall:\n";
    echo 
"<BR>Oft muss auch in den Spalten (bzw. Zeilen, wenn die drei Boxen untereinander liegen) nachgesehen werden, ob eine Stelle f&uuml;r die bestimmte Zahl frei ist. In diesem Beispiel kann die Zahl 7 wieder nur in der dritten Zeile der rechten Box (OR) liegen. Da aber in der 8. Spalte in der darunter liegenden Box (MR) schon eine 7 steht, bleibt wieder nur die letzte Spalte (mit kleinem x markiert) als Zielort &uuml;brig.\n";
  
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(000070000));
    
show_row(array(700000000));
    
show_row(array(00000140"<INPUT TYPE=TEXT VALUE=\"x\" SIZE=1 MAXLENGTH=1>"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(000000070));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
    
    echo 
"<LI>Erweiterte oder indirekte Dreier-Methode (Wert: 4 Punkte, Farbmarkierung: <FONT COLOR=$farbe_rot>Rot</FONT>): Bestimme den Ort der dritten Zahl ohne genaue Kenntnis des Ortes der zweiten Zahl:\n";
    echo 
"<BR>Hier nutzt man aus, dass die Position der zweiten Zahl zwar noch nicht genau bekannt ist, aber auf eine Zeile oder Spalte einer Box beschr&auml;nkt werden kann. Dann folgt der Ort f&uuml;r die dritte Zahl analog der oben beschriebenen Methode A. Dieses Verfahren kann in bestimmten F&auml;llen auch ohne Kenntnis der ersten Zahl funktionieren.</LI>\n";
  
    echo 
"<P>Einfacher Fall:\n";
    echo 
"<BR>Im einfachen Fall wei&szlig; man, dass in der rechten Box (OR) die Zahl 6 nur in der zweiten Zeile sein kann, da die erste Zeile nicht in Frage kommt (wegen der 6 in Spalte 9) - die genaue Position der Zahl 6 in der mittleren Zeile von Box OR ist aber noch unbekannt. Trotzdem kann man daraus schlie&szlig;en, dass in der ersten Box (OL) die 6 nur in der dritten Zeile sein kann; in dieser Zeile bleibt dann nur die zweite Spalte als einzig m&ouml;glicher Ort &uuml;brig (mit kleinem x markiert).\n";
  
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(547000280));
    
show_row(array(800002000));
    
show_row(array(2"<INPUT TYPE=TEXT VALUE=\"x\" SIZE=1 MAXLENGTH=1>"3000549));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(000000006));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"<P>Komplexerer Fall:\n";
    echo 
"<BR>Wegen der Zahl 7 in der rechten mittleren Box (MR) kann in der davor liegenden Box (MM) die 7 nicht in Zeile 5 stehen. Damit bleiben als m&ouml;glicher Ort f&uuml;r die 7 in dieser Box nur die beiden Positionen in der Spalte 5 &uuml;brig (mit kleinem a markiert).\n";
    echo 
"<BR>Nun kann man &auml;hnlich wie im einfachen Fall folgern, dass in der dar&uuml;ber liegenden Box (OM) die Zahl 7 nur in der oberen Zeile sein kann (Spalte 4 oder 6), wobei die genaue Position aber noch unbekannt ist. Also muss in der rechts davon liegenden Box (OR) die 7 wieder in der 3. Zeile sein. Da aber in der 8. Spalte in der darunter liegenden Box (MR) schon eine 7 steht, bleibt wieder nur die letzte Spalte (mit kleinem x markiert) als Zielort &uuml;brig.\n";
    echo 
"<P>Alternativ kann man auch argumentieren, dass die Zahl 7 in der 3. Zeile nicht in Box OL stehen kann (in dieser Box ist schon eine 7), auch nicht in Box OM wegen der 7 irgendwo in Spalte 5 von Box MM (siehe oben, mit kleinem a markiert), aber auch nicht in Spalte 8 der Box OR (siehe oben), und somit bleibt dort nur die Spalte 9 (mit kleinem x markiert) als Zielort &uuml;brig.\n";
  
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(000000000));
    
show_row(array(700000000));
    
show_row(array(00020140"<INPUT TYPE=TEXT VALUE=\"x\" SIZE=1 MAXLENGTH=1>"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(0003"<INPUT TYPE=TEXT VALUE=\"a\" SIZE=1 MAXLENGTH=1>"2000));
    
show_row(array(000000070));
    
show_row(array("...""...""..."5"<INPUT TYPE=TEXT VALUE=\"a\" SIZE=1 MAXLENGTH=1>"8"...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
    
    echo 
"<LI>Einzig m&ouml;gliche Zahl (Wert: 6 Punkte, Farbmarkierung: <FONT COLOR=$farbe_blau>Blau</FONT>): Einzige noch fehlende Zahl an einem bestimmtem Ort:\n";
    echo 
"<BR>Man untersucht f&uuml;r einen Ort, welche der 9 Zahlen dort stehen k&ouml;nnten, wobei die Sudoku-Regeln ber&uuml;cksichtigt werden m&uuml;ssen. Bleibt nur eine Zahl &uuml;brig, hat man die L&ouml;sung f&uuml;r diese Stelle gefunden. Das klingt zwar einfach, ist aber nicht so leicht zu erkennen.</LI>\n";
  
    echo 
"<P>Beispiel: Die einzige Zahl an der Position Zeile 3 und Spalte 4 (mit kleinem x markiert) kann nur die Zahl 7 sein, weil alle anderen Zahlen schon in gleicher Zeile (1, 4, 8, 9), in gleicher Spalte (2, 5), bzw. in gleicher Box (1, 2, 3, 6) vorhanden sind.\n";
  
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(000260000));
    
show_row(array(000003000));
    
show_row(array(080"<INPUT TYPE=TEXT VALUE=\"x\" SIZE=1 MAXLENGTH=1>"01409));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(000500070));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
    
    echo 
"<LI>Vollst&auml;ndige Ausd&uuml;nnung mit einstelliger Restzahl bzw. einziger Kandidatenzahl (Wert: 1 Basis-Punkt, Farbmarkierung: <FONT COLOR=$farbe_braun>Braun</FONT>): Hat man nach einem oder mehreren Ausd&uuml;nnschritten einen Rest so weit verkleinert, dass er nur noch aus einer Zahl besteht, ist diese Zahl die L&ouml;sung f&uuml;r die betrachtete Stelle.</LI>\n";
  
    echo 
"<P>Ausd&uuml;nnung:\n";
    echo 
"<BR>Hier wird davon ausgegangen, dass zuerst versucht wird, das Sudoku ohne Anschreiben der Reste (das sind die Kandidaten, also die m&ouml;glichen Zahlen f&uuml;r die jeweilige Stelle) zu l&ouml;sen (Methoden A, B und C). Kommt man damit nicht weiter, muss man f&uuml;r jede freie Stelle alle Zahlen aufschreiben, die f&uuml;r diese Stelle in Frage kommen (also die daf&uuml;r &uuml;berhaupt noch m&ouml;glichen Zahlen): Das sind die Kandidaten f&uuml;r die jeweilige Stelle, die hier als Ganzes \"Rest\" genannt und auch der Einfachheit halber als eine mehrstellige Zahl (ohne Komma oder andere Trennzeichen unterhalb der Eingabefelder) geschrieben werden.\n";
    echo 
"<BR>Danach versucht man, diese Reste so lange \"auszud&uuml;nnen\", also zu verk&uuml;rzen, bis man zu einer eindeutigen L&ouml;sung f&uuml;r eine Stelle kommt (Methoden D und E). Die Ausd&uuml;nn-Methoden I bis V werden im n&auml;chsten Abschnitt ausf&uuml;hrlich beschrieben.\n";
  
    echo 
"<P>Beispiel:\n";
    echo 
"<BR>Nach der Ausd&uuml;nn-Methode I (siehe weiter unten im n&auml;chsten Abschnitt) kommt die Zahl 9 innerhalb der zweiten Zeile nur in der ersten Box (OL) vor: Daher muss die 9 dort sein (auch wenn man die Position innerhalb der zweiten Zeile noch nicht wei&szlig;) - sie kann also nicht in der dritten Zeile dieser Box noch einmal vorkommen. Daher kann man aus den Resten dieser Zeile in der Box OL den Kandidaten 9 streichen (d.h.: 249 wird zu 24, 39 wird zu 3).\n";
    echo 
"<BR>Damit bleibt an der Position Zeile 3 und Spalte 3 (mit kleinem x markiert) nur noch die 3 als Kandidat &uuml;brig. Also hat man einen eindeutigen Rest an dieser Stelle gefunden.\n";
  
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(500987000,
                    
"""246""36""""""""1234""1234""1234"));
    
show_row(array(100004865,
                    
"""279""379""23""23"""""""""));
    
show_row(array(80"<INPUT TYPE=TEXT VALUE=\"x\" SIZE=1 MAXLENGTH=1>"165700,
                    
"""249""39""""""""""2349""2349"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(004000000));
    
show_row(array(032000000));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
    
    echo 
"<LI>Vollst&auml;ndige Ausd&uuml;nnung mit einzig auftretender Restzahl (alleine auftretender Kandidat) (Wert: 4 Basis-Punkte, Farbmarkierung: <FONT COLOR=$farbe_lila>Lila</FONT>): Hat man nach einem oder mehreren Ausd&uuml;nnschritten mehrere Reste so weit verkleinert, dass eine bestimmte Zahl nur noch an einer einzigen Stelle innerhalb der Reste einer Zeile, einer Spalte oder einer Box vorkommt, ist diese Zahl L&ouml;sung f&uuml;r diese Stelle.</LI>\n";
  
    echo 
"<P>Beispiel:\n";
    echo 
"<BR>Nach der Ausd&uuml;nn-Methode III (siehe weiter unten im n&auml;chsten Abschnitt) findet man in der Box OR das Reste-Paar 79 zwei Mal. Die Zahlen 7 und 9 m&uuml;ssen also an diesen beiden Stellen auftreten. Damit k&ouml;nnen in allen anderen Resten dieser Box die Zahlen 7 und 9 gestrichen werden. Daraus folgt, dass an der Position Zeile 1 und Spalte 4 (mit kleinem x markiert) die Zahl 7 stehen muss.\n";
  
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(264"<INPUT TYPE=TEXT VALUE=\"x\" SIZE=1 MAXLENGTH=1>"90083,
                    
"""""""157""""15""157"""""));
    
show_row(array(000200640,
                    
"1579""1579""1579""""3578""1358""""""79"));
    
show_row(array(380064020,
                    
"""""1579""1357""""""1579""""79"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(000602801));
    
show_row(array(000817005));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"</OL>\n";
  
    echo 
"<H4>F&uuml;nf Methoden zur Ausd&uuml;nnung der Reste (I bis V)</H4>\n";
  
    echo 
"Der Begriff der Ausd&uuml;nnung zur Verk&uuml;rzung der Reste wurde im vorherigen Abschnitt unter Methode D schon erl&auml;tert. Im Allgemeinen sind, um eine L&ouml;sung zu finden, immer mehrere Ausd&uuml;nnschritte notwendig (bis zu 23 direkt nacheinander wurden schon beobachtet!). Manche Schritte helfen dabei nicht zur L&ouml;sungsfindung, aber das wei&szlig; man vorher nicht.\n";
    echo 
"<BR>&Uuml;ber die H&auml;lfte (56 %) aller hier berechneten Sudokus sind nur durch Anschreiben der Reste und anschlie&szlig;ender Ausd&uuml;nnung l&ouml;sbar!\n";
    echo 
"<BR>In den folgenden Beispielen werden oft nur Teile eines Sudokus mit entsprechenden Resten dargestellt, um das Ganze &uuml;bersichtlicher zu machen; es sind Ausschnitte aus aktuellen Sudokus.\n";
  
    echo 
"<OL TYPE=\"I\">\n";
  
    echo 
"<LI>Box-Test der Reste in einer Zeile oder Spalte: Man sieht in den Resten einer Box nach, ob innerhalb einer Zeile bzw. Spalte eine Zahl vorkommt, die nur genau in dieser Box auftaucht. Diese Zahl muss also innerhalb dieser Box in der gefundenen Zeile bzw. Spalte stehen (wobei die genaue Position noch unbekannt ist), sie kann dann aber aus den anderen Zeilen bzw. Spalten innerhalb dieser Box gestrichen werden. Dies ist die am h&auml;ufigsten auftretende Methode, um die Reste auszud&uuml;nnen: 48 %!</LI>\n";
  
    echo 
"<BR>Bewertung: F&uuml;r jedes Vorkommen gibt es 4 Punkte.\n";
  
    echo 
"<P>Beispiel:\n";
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(053479060,
                    
"28""""""""""""12""""128"));
    
show_row(array(700005004,
                    
"""1289""12689""136""136""""1239""12389"""));
    
show_row(array(400802070,
                    
"""19""169""""136""""1359""""1359"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(160000800));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"<BR>Hier findet man z.B. die Zahl 1: Sie ist innerhalb der ersten Zeile nur in den Resten der rechten Box OR vorhanden (rot gef&auml;rbte Reste). Also kann man in den anderen Zeilen dieser Box diese Zahl aus den Resten streichen - das wird hier durch die Darstellung in eckigen Klammern hervorgehoben. Damit bleibt &uuml;brig:\n";
  
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(053479060,
                    
"28""""""""""""<FONT COLOR=$farbe_rotgelb>12</FONT>""""<FONT COLOR=$farbe_rotgelb>128</FONT>"));
    
show_row(array(700005004,
                    
"""1289""12689""136""136""""[1]239""[1]2389"""));
    
show_row(array(400802070,
                    
"""19""169""""136""""[1]359""""[1]359"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(160000800));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"<LI>Zeilen-/Spalten-Test der Reste innerhalb einer Box: Man sieht in den Resten nach, ob innerhalb einer Box eine Zahl vorkommt, die nur genau in einer Zeile bzw. Spalte dieser Box auftaucht - diese Zahl muss dann in dieser Zeile bzw. Spalte dieser Box stehen (wobei die genaue Position noch unbekannt ist). Dann kann man in den anderen Resten dieser Zeile bzw. Spalte au&szlig;erhalb der Box diese Zahl streichen.</LI>\n";
  
    echo 
"<BR>Bewertung: F&uuml;r jedes Vorkommen gibt es 6 Punkte.\n";
  
    echo 
"<P>Beispiel:\n";
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(305000006,
                    
"""789""""12789""12489""124789""1479""1479"""));
    
show_row(array(040506020,
                    
"178""""1789""""1389""""1379""""1379"));
    
show_row(array(602000800,
                    
"""79""""1379""1349""13479""""134579""134579"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(910472000));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"<BR>Hier findet man z.B. die Zahl 1: Sie ist in den Resten der Box OL nur in der zweiten Zeile vorhanden (rot gef&auml;rbte Reste), nicht in den anderen Zeilen dieser Box. Also kann man in den anderen Resten dieser Zeile in den anderen beiden Boxen diese Zahl streichen (durch die Darstellung in eckigen Klammern hervorgehoben). Damit bleibt &uuml;brig:\n";
  
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(305000006,
                    
"""789""""12789""12489""124789""1479""1479"""));
    
show_row(array(040506020,
                    
"<FONT COLOR=$farbe_rotgelb>178</FONT>""""<FONT COLOR=$farbe_rotgelb>1789</FONT>""""[1]389""""[1]379""""[1]379"));
    
show_row(array(602000800,
                    
"""79""""1379""1349""13479""""134579""134579"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(910472000));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"<LI>Man sucht in einer Zeile, Spalte oder Box nach N-Tupel, also danach, dass bestimmte Kandidaten an nur wenigen Stellen auftreten: Genauer hei&szlig;t das, dass man N zusammen geh&ouml;rende Stellen (innerhalb einer Zeile, Spalte oder Box) sucht, in denen genau N verschiedene Kandidaten auftreten. Wenn an N Stellen alle oder ein Teil der N betrachteten Kandidaten stehen, k&ouml;nnen diese Kandidaten nur an diesen N Stellen auftreten (wobei die Verteilung noch unbekannt ist), diese Kandidaten k&ouml;nnen dann aber aus den anderen Resten gestrichen werden.</LI>\n";
  
    echo 
"<BR>Es gibt 2-Tupel (Doppel), 3-Tupel (Tripel), 4-Tupel (Quadrupel), 5-Tupel (Pentupel), 6-Tupel und 7-Tupel (8-Tupel machen keinen Sinn, da dann die neunte Zahl eindeutig ist und somit direkt gefunden werden kann).\n";
  
    echo 
"<BR>Bewertung: F&uuml;r jedes N-Tupel gibt es 2*N Punkte.\n";
  
    echo 
"<P>Einfaches Beispiel mit 2-Tupel (Doppel):";
  
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(602010800,
                    
"""79""""79""""3479""""34579""34579"));
    
show_row(array(040506020,
                    
"189""""179""""3789""""1379""""1379"));
    
show_row(array(305000006,
                    
"""1789""""2789""24789""2479""1479""1479"""));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(708400000));
    
show_row(array(000308000));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"<BR>Hier findet man z.B. in der ersten Zeile das 2-Tupel 79 (Doppel: 79, 79), als rot gef&auml;rbte Reste markiert; die beiden Kandidaten 7 und 9 m&uuml;ssen also an diesen beiden Stellen sein. Also kann man in den anderen Resten dieser Zeile diese beiden Zahlen streichen (durch die Darstellung in eckigen Klammern hervorgehoben). Damit bleibt &uuml;brig:\n";
  
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(602010800,
                    
"""<FONT COLOR=$farbe_rotgelb>79</FONT>""""<FONT COLOR=$farbe_rotgelb>79</FONT>""""34[7][9]""""345[7][9]""345[7][9]"));
    
show_row(array(040506020,
                    
"189""""179""""3789""""1379""""1379"));
    
show_row(array(305000006,
                    
"""1789""""2789""24789""2479""1479""1479"""));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(708400000));
    
show_row(array(000308000));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";

    echo 
"<P>Kurzes Beispiel mit 3-Tupel (Tripel):\n";
    echo 
"<BR>Hier findet man in der Box OM (und in der 5. Spalte) das 3-Tupel 235 (Tripel: 235, 23, 25). Damit k&ouml;nnen in allen anderen Resten dieser Box (und in der 5. Spalte) die Zahlen 2, 3 und 5 gestrichen werden.\n";
    
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(040009010,
                    
"""""""2357""235"""""""""));
    
show_row(array(010608005,
                    
"""""""""23"""""""""));
    
show_row(array(003000000,
                    
"""""""12457""25""12457"""""""));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(000070000));
    
show_row(array(000040000));
    
show_row(array("...""...""...""..."1"...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"<P>Relativ h&auml;ufig (in etwa 10% aller N-Tupel-F&auml;lle) findet man noch 4-Tupel (z.B. das Quadrupel 1479 mit: 147, 17, 79, 49), aber 5-Tupel, 6-Tupel und 7-Tupel sind sowohl noch seltener (2 %) als auch schwieriger zu erkennen...\n";

    echo 
"<LI>X-Wing-Methode: Man sieht in den Resten nach, ob es zwei Zeilen gibt, in denen in den Resten eine bestimmte Zahl in genau zwei Spalten vorkommt, wobei aber die Position der gefundenen Spalten in beiden Zeilen &uuml;bereinstimmen muss. Dann wei&szlig; man, dass diese Zahl entweder als erste in der ersten Zeile und als zweite in der zweiten Zeile vorkommen muss oder umgekehrt als zweite in der ersten Zeile und dann als erste in der zweite Zeile. Diese 4 M&ouml;glichkeiten bilden das \"X\". Also kann man in den Spalten, die zu dem \"X\" geh&ouml;ren, diese Zahl in allen anderen Zeilen streichen.</LI>\n";
  
    echo 
"<P>Das Ganze gilt entsprechend f&uuml;r Spalten: Man sieht in den Resten nach, ob es zwei Spalten gibt, in denen in den Resten eine bestimmte Zahl in genau zwei Zeilen vorkommt, wobei aber die Position der gefundenen Zeilen in beiden Spalten &uuml;bereinstimmen muss. Dann kann man in den Zeilen, die zu dem \"X\" geh&ouml;ren, diese Zahl in allen anderen Spalten streichen.\n";
  
    echo 
"<BR>Bewertung: F&uuml;r jedes Vorkommen gibt es 10 Punkte.\n";
  
    echo 
"<P>Beispiel:\n";
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(803902147,
                    
"""56""""""56"""""""""));
    
show_row(array(009041830,
                    
"567""2567""""56""""""""""25"));
    
show_row(array(001738690,
                    
"45""245""""""""""""""25"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(008029300,
                    
"1457""1457""""56""""""""167""146"));
    
show_row(array(306804209,
                    
"""157""""""157""""""17"""));
    
show_row(array(2"...""...""...""...""...""..."5"..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"<BR>Hier findet man z.B. f&uuml;r die Zahl 5: Sie ist in den Resten der ersten Zeile nur in Spalte 2 und 5 vorhanden, aber auch in f&uuml;nften Zeile nur in Spalte 2 und 5 (diese Positionen bilden das namensgebende \"X\"). An zwei gegen&uuml;berliegenden Stellen des \"X\" muss also die Zahl 5 liegen (rot gef&auml;rbte Reste), und deshalb kann in den anderen Zeilen die 5 in den Spalten 2 und 5 gestrichen werden (durch die Darstellung in eckigen Klammern hervorgehoben). Damit bleibt &uuml;brig:\n";
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(803902147,
                    
"""<FONT COLOR=$farbe_rotgelb>56</FONT>""""""<FONT COLOR=$farbe_rotgelb>56</FONT>"""""""""));
    
show_row(array(009041830,
                    
"567""2[5]67""""56""""""""""25"));
    
show_row(array(001738690,
                    
"45""24[5]""""""""""""""25"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(008029300,
                    
"1457""14[5]7""""56""""""""167""146"));
    
show_row(array(306804209,
                    
"""<FONT COLOR=$farbe_rotgelb>157</FONT>""""""<FONT COLOR=$farbe_rotgelb>157</FONT>""""""17"""));
    
show_row(array(2"...""...""...""...""...""..."5"..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"<LI>Goldene Kette:</LI>\n";
    echo 
"<P>Eine Goldene Kette (Golden Chain, manchmal auch Remote Pairs genannt) ist eine Reihe von Paaren vom Typ ab, bc, cd, de, ef, ..., xy, yz, za, von denen jeweils zwei aufeinanderfolgende Paare in der gleichen Zeile, Spalte oder Box sind und die eine gemeinsame Zahl besitzen. Wenn die Zahl des ersten Paars, die nicht im zweiten Paar vorkommt (hier bei ab also a) mit der Zahl des letzten Paars, die nicht im vorletzten Paar vorkommt (bei za also auch a), &uuml;bereinstimmt, dann kann man alle Zahlen a streichen, die sowohl von dem ersten als auch dem letzten Paar aus \"gesehen\" werden, also in der jeweils gleichen Zeile, Spalte oder Box liegen, weil die Zahl a auf jeden Fall entweder an der Stelle des ersten oder des letzten Paars vorkommt (wenn a im ersten Paar vorkommt, ist das offensichtlich; kommt aber b vor, so muss im zweiten Paar c sein, daher im dritten Paar d usw., bis zu z im vorletzten Paar, also a im letzten Paar).\n";
  
    echo 
"<BR>Bewertung: Hierbei gibt es 3*N Punkte entsprechend der L&auml;nge N der gefundenen Kette (3 bis 14 = l&auml;ngste bisher gefundene Kette, aber l&auml;ngere sind durchaus vorhanden - L&auml;ngen &uuml;ber 20 wurden schon beobachtet).\n";
  
    echo 
"<P>Literatur:\n";
    echo 
"<BR>Download des Artikels von Eduyng Castan: <A HREF=http://www.coverpop.com/sfiles/Sudoku-GoldenChains.pdf>http://www.coverpop.com/sfiles/Sudoku-GoldenChains.pdf</A>\n";
    echo 
"<BR>&Auml;hnlicher Artikel von Mihail Iusut: <A HREF=http://www.scanraid.com/sudoku/Remote_Pairs_and_XY_Chains.pdf>http://www.scanraid.com/sudoku/Remote_Pairs_and_XY_Chains.pdf</A>\n";
  
    echo 
"<P>Beispiel einer Goldenen Kette (nach wenigen anderen Ausd&uuml;nnschritten):\n";
    echo 
"<P><TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
show_row(array(806495001,
                    
"""<FONT COLOR=$farbe_rotgelb>27</FONT><SUB>1</SUB>""""""""""<FONT COLOR=$farbe_rotgelb>37</FONT><SUB>2</SUB>""23""",));
    
show_row(array(030876590,
                    
"1[2]""""124""""""""""""24"));
    
show_row(array(590000860,
                    
"""""47""23""123""12""""""47"));
    echo 
"<TR><TD COLSPAN=11><HR></TD></TR>\n";
    
show_row(array(069040058,
                    
"<FONT COLOR=$farbe_rotgelb>12</FONT><SUB>4</SUB>""""""237""""27""<FONT COLOR=$farbe_rotgelb>13</FONT><SUB>3</SUB>""""",));
    
show_row(array(708509406,
                    
"""1[2]""""""23""""""13"""));
    
show_row(array("...""...""...""...""...""...""...""...""..."));
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
    
// Nur 1 Doppel davor: 030200004107439280040000030904086372308042000020300048400003820000804003683027410
  
    
echo "<BR>Die gefundene Goldene Kette ist: (1:2)<FONT COLOR=$farbe_rotgelb>27</FONT> - (1:7)<FONT COLOR=$farbe_rotgelb>73</FONT> - (4:7)<FONT COLOR=$farbe_rotgelb>31</FONT> - (4:1)<FONT COLOR=$farbe_rotgelb>12</FONT>.\n";
    echo 
"Beachte, dass hier die Reihenfolge der Zahlen innerhalb eines Doppels dem Verkettungs-Prinzip angepasst ist: Also 73 statt der sonst aufsteigenden Reihenfolge 37 und 31 statt sonst 13. Das jeweilige Ende der Goldenen Kette ist also die Zahl 2, die daher im Feld (2:1), also Zeile 2 und Spalte 1, und im Feld (5:2), also Zeile 5 und Spalte 2, gestrichen werden kann.\n";
    echo 
"<BR>Identisch mit der gefundenen Goldenen Kette ist auch die in umgekehrter Reihenfolge: (4:1)<FONT COLOR=$farbe_rotgelb>21</FONT> - (4:7)<FONT COLOR=$farbe_rotgelb>13</FONT> - (1:7)<FONT COLOR=$farbe_rotgelb>37</FONT> - (1:2)<FONT COLOR=$farbe_rotgelb>72</FONT>.\n";
  
    echo 
"<P>Es wurden 16 Sudokus gefunden, die in den im Web zur Verf&uuml;gung stehenden 30 Sekunden nicht gel&ouml;st werden konnten. Hier drei Beispiele einer Batch-Rechnung - auffallend die immer l&auml;nger werdenden Ketten mit immer mehr Alternativen (bei allen bisher gel&ouml;sten Sudokus waren nicht mehr als 2770 Ketten einer L&auml;nge aufgetreten):\n";
    echo 
"<UL>\n";
  
    echo 
"<LI><A HREF=\"$php_self?000030080300000409054006700060178000400000510003000027007001000800300900092780000_0\" target=\"_blank\">000030080300000409054006700060178000400000510003000027007001000800300900092780000</A></LI>";
    echo 
"<BR>Nach 7 gefundenen Goldenen Ketten waren noch 25 Paare &uuml;brig. Daraus ergaben sich dann 210 Ketten der L&auml;nge 3 (aber keine Goldenen), 424 der L&auml;nge 4, ..., 18662 der L&auml;nge 13. Dann wurde aber abgebrochen, da der Programm-Hauptspeicher (hier 8 MB) &uuml;berschritten wurde. Dieses Sudoku ist trotzdem eindeutig l&ouml;sbar (bei 2 Einsetzversuchen gefunden), wenn auch bisher nicht mit diesem Programm...\n";
  
    echo 
"<LI><A HREF=\"$php_self?042000590809000002000209000206040000050000614004076000000608009408000003061000750_0\" target=\"_blank\">042000590809000002000209000206040000050000614004076000000608009408000003061000750</A></LI>";
    echo 
"<BR>Nach 8 gefundenen Goldenen Ketten waren noch 30 Paare &uuml;brig. Daraus ergaben sich dann 134 Ketten der L&auml;nge 3 (aber keine Goldenen), ..., 90886 der L&auml;nge 18, 86514 der L&auml;nge 19. Dann wurde aber - nach &uuml;ber 1 Stunde - mit \"Bus error\" abgebrochen. Auf einem anderen Rechner wurde weiter gerechnet bis 6436 Ketten der L&auml;nge 25, 1160 der L&auml;nge 25, dann aber keine Kette der L&auml;nge 27. Das f&uuml;hrte zu Einsetzversuchen, bei der es nach 6 Versuchen in 3 Rekursionen zu 4 L&ouml;sungen f&uuml;hrte => also ist dieses kein wirkliches Sudoku.\n";
    
    echo 
"<LI><A HREF=\"$php_self?568002070003070090000500200000007100204089007005300000001005302080060900050900040_0\" target=\"_blank\">568002070003070090000500200000007100204089007005300000001005302080060900050900040</A></LI>";
    echo 
"<BR>Nach 5 gefundenen Goldenen Ketten waren noch 27 Paare &uuml;brig. Daraus ergaben sich dann 296 Ketten der L&auml;nge 3 (aber keine Goldenen), 628 der L&auml;nge 4, ..., 268106 der L&auml;nge 15, 355184 (!) der L&auml;nge 16. Dann wurde aber - nach 72 Minuten - abgebrochen, da der Programm-Hauptspeicher von 128 MB &uuml;berschritten wurde. Einsetzversuche ergaben nach 2 Versuchen 2 L&ouml;sungen => also ist dieses kein wirkliches Sudoku.\n";
  
    
/*
    Alle bisher nicht loesbaren (weil abgebrochene) Sudokus:
    000030080300000409054006700060178000400000510003000027007001000800300900092780000   <= Aber eindeutig loesbar!
    030040906000001000000068470000000081004006703823000009002000000000009067687015090
    042000590809000002000209000206040000050000614004076000000608009408000003061000750
    042000590809000002000209000206040000050000614004076000000608009408000063061000750
    042000590809000002000209000206040000050000614004076000000608009408000063061000758
    042000590809000002000209000206040000050000614004076005000608009408000063061000758
    042000590809000002000209000206040000057000614004076000000608009408000060061000750
    042000590809000002000209000206040000057000614004076000000608009408000060061000758
    042000590809000002000209000206040000057000614004076005000608009408000060061000758
    042000590809000002000209000206040007050000614004076005000608009408000063061000758
    042000590809000002000209000206040007050000614104076005000608009408000063061000758
    042000590809000002000209000206040007057000614004076005000608009408000060061000758
    042000590809000002000209000206040007057000614104076005000608009408000060061000758
    530070000600195000098000060800040003400803001700020006060000040000419005000000079
    568002070003070090000500200000007100204089007005300000001005302080060900050900040
    568192473123070095040530210030057100214689537075300000091045302480063951350900740
    */
  
    
echo "</UL>\n";
  
    echo 
"</OL>\n";
  
    echo 
"<H4>Allgemeines</H4>\n";
    echo 
"<P>Die Punktzahlen sind so einigerma&szlig;en den Schwierigkeitsgraden angepasst. Sie h&auml;ngen aber auch von der Reihenfolge im Programm ab - so ergibt eine andere Reihenfolge im Suchen von Mustern in den Resten etwas andere Werte. Gerade die Bewertung beim Ausd&uuml;nnen ist schwierig: es werden alle Ausd&uuml;nnschritte mitgez&auml;hlt, egal, ob sie am Ende etwas bringen oder nicht. Aber das wei&szlig; man ja auch beim L&ouml;sen mit Hand vorher nicht...\n";
  
    echo 
"<P>Ab 50 Punkten wird es interessant, &uuml;ber 75 Punkte ist es schon schwerer, &uuml;ber 100 Punkte wirklich schwer, und &uuml;ber 125 Punkte ist schon eine Herausforderung. Der Mittelwert aller Sudokus liegt bei 106 Punkten (der Hauptwert liegt <A HREF=\"verteilung.ohne.ausduennung.pdf\">um 60 Punkte ohne Ausd&uuml;nnung (siehe Kurve)</A>, und <A HREF=\"verteilung.mit.ausduennung.pdf\">um 144 Punkte mit Ausd&uuml;nnung (siehe Kurve)</A>). Aktuelles Maximum mit schwer zu &uuml;berbietenden 516 Punkten (sehr viel mehr Punkte sind wohl kaum erreichbar?!), also das bisher am schwersten (hier) gel&ouml;ste Sudoku:\n";
    echo 
"<UL>\n";
  
?>
<LI>Bisher: 454 Punkte aus 23 Zahlen (erste einfache Schritte: 11, Verh&auml;ltnis 7.8): - A: 50, B: 0, C: 2, D: 5, E: 1, Ausduennschritte: 28, N-Tupel: 3 (bis Tripel), X-Wings: 0, Goldene Ketten: 16 (maximal 10 lang) - in 17 sec: <BR><A HREF="<? echo $php_self?>?000000070003805906050403080047000320000000000020000100000204050506100000080000000_0" target="_blank">000000070003805906050403080047000320000000000020000100000204050506100000080000000</A></LI>

<LI>Neu (Dank an Michael Jentsch): 516 Punkte aus 25 Zahlen (erste einfache Schritte: 6, Verh&auml;ltnis 9.2): - A: 48, B: 0, C: 1, D: 4, E: 3, Ausduennschritte: 28, N-Tupel: 1 (bis Tripel), X-Wings: 0, Goldene Ketten: 17 (maximal 11 lang) - in 18 sec: <BR><A HREF="<? echo $php_self?>?507000040003100009000000800000503100002010950070004600006000000380000000009280306_0" target="_blank">507000040003100009000000800000503100002010950070004600006000000380000000009280306</A></LI>

<LI>PS: Ohne Goldene Ketten liegt das Maximum bei 217 Punkten aus 17 Zahlen (erste einfache Schritte: 2, Verh&auml;ltnis 3.4): - A: 51, B: 2, C: 0, D: 8, E: 3, Ausduennschritte: 20, N-Tupel: 4 (bis Quadrupel), X-Wings: 0, Goldene Ketten: 0 - in 1.5 sec: <BR><A HREF="<? echo $php_self?>?008000000000002540031060000000000070000400200063000000000000001500007000000080003_0" target="_blank">008000000000002540031060000000000070000400200063000000000000001500007000000080003</A></LI>
<?

    
echo "</UL>\n";
    echo 
"Das 454-Punkte-Sudoku wurde durch Reduzierung aller bis dahin gel&ouml;sten etwa 9200 Sudokus in einem Aufwand von &uuml;ber 2100 Stunden Rechenzeit (insgesamt wurden fast 3 Millionen Sudokus durchgerechnet) gefunden... Reduzierung hei&szlig;t hier: L&auml;sst man aus einem Sudoku mit N Zahlen jeweils eine Zahl aus, so entstehen N Sudokus mit jeweils N-1 Zahlen, die alle berechnet werden. Gibt es dabei L&ouml;sungen, macht man die gleiche Prozedur mit dem berechneten Sudoku, das die h&ouml;chste Punktzahl hat, usw., bis es keine L&ouml;sung mehr gibt.\n";
  
    echo 
"<H4>Etwas Statistik:</H4>\n";
    echo 
"Bei bisher nun insgesamt etwa 22100 gel&ouml;sten Sudokus wurden etwa 1197000 mal die Methoden A bis E eingesetzt; davon 94.5% f&uuml;r Methode A, 2.8% (0.8%  + 2.0%) Methode B+C, und 2.7% (1.9% + 0.8%) Methode D+E (also Ausd&uuml;nnung). Die Ausd&uuml;nn-Methoden werden zwar selten gebraucht, sind aber trotzdem zur L&ouml;sung von knapp der H&auml;lfte aller Sudokus notwendig!\n";
  
    echo 
"<P>Genauer gesehen waren etwa 26% der Sudokus allein mit Methode A l&ouml;sbar, insgesamt 54% nur mit den  Methoden A+B+C. Das sind die einfacheren Sudokus, obwohl dabei immerhin auch etwa 100 Punkte erreicht werden k&ouml;nnen - bisheriges Maximum: 96, also die (hier) schwierigsten Sudokus ohne Ausd&uuml;nnung:\n";
    echo 
"<UL>\n";
  
?>
<LI>96 Punkte aus 23 Zahlen (erste einfache Schritte: 58, Verh&auml;ltnis 1.7): - A: 48, B: 0, C: 10, D: 0, E: 0, Ausduennschritte: 0, N-Tupel: 0, X-Wings: 0, Goldene Ketten: 0 - in 0.5 sec: <BR><A HREF="<? echo $php_self?>?371600500000000300025000700054000000000102090200008004100000000000029001000830000_0" target="_blank">371600500000000300025000700054000000000102090200008004100000000000029001000830000</A></LI>
<LI>96 Punkte aus 24 Zahlen (erste einfache Schritte: 57, Verh&auml;ltnis 1.7): - A: 47, B: 0, C: 10, D: 0, E: 0, Ausduennschritte: 0, N-Tupel: 0, X-Wings: 0, Goldene Ketten: 0 - in 0.8 sec: <BR><A HREF="<? echo $php_self?>?000050007940000020000000040001200098086045000000100000600037010002060000038000400_0" target="_blank">000050007940000020000000040001200098086045000000100000600037010002060000038000400</A></LI>
<?

    
echo "</UL>\n";
    echo 
"Obwohl in einem weiteren Aufwand von etwa 550 Stunden Rechenzeit (insgesamt fast 2 Millionen Sudokus wurden durchgerechnet) alle Sudokus ohne Ausd&uuml;nnung nach einem analogen Verfahren wie oben beschrieben reduziert wurden, konnte kein Sudoku gefunden werden, das mehr als 100 Punkte hat. Es d&uuml;rfte also schwierig sein, ein Sudoku ohne Ausd&uuml;nnung mit h&ouml;herer Punktzahl zu finden.\n";
  
    echo 
"<P>F&uuml;r die etwa 10200 Sudokus (46% der F&auml;lle), bei denen die Kandidaten/Reste analysiert werden mussten, waren insgesamt etwa 81000 Ausd&uuml;nnschritte notwendig (davon 48 % Box-Tests, 7 % Zeilen-/Spalten-Tests, 20.5 % N-Tupel, 2.5 % X-Wings, 22 % Goldene Ketten). In einem Fall waren es 23 Ausd&uuml;nnschritte hintereinander, bis eine Zahl gefunden werden konnte, und in einem anderen Fall insgesamt 33 Schritte!\n";
  
    echo 
"<P>Dabei konnten etwa 1350 alleine durch die einfachen Box-Test- und Zeilen-/Spalten-Test-Methoden gel&ouml;st werden. Etwa 2950 Sudokus wurden durch die N-Tupel-Methode (darunter ein 7-Tupel!), nur 260 Sudokus durch die X-Wing-Methode (erstaunlich wenig!, aber immerhin wurden insgesamt etwa 1900 X-Wings gefunden), jedoch 5650 durch die Goldene Kette gel&ouml;st (bei insgesamt gut 17700 gefundenen Goldenen Ketten, und in einzelnen Sudokus bis zu 20 Goldenen Ketten bzw. maximal mit der L&auml;nge 14) - insofern verwundert es, dass dieses Verfahren so wenig bekannt ist!\n";
  
    echo 
"<H4>Literatur:</H4>\n";
    echo 
"Allgemeine L&ouml;sungsstrategien bei: <A HREF=http://www.sadmansoftware.com/sudoku/solvingtechniques.htm>http://www.sadmansoftware.com/sudoku/solvingtechniques.htm</A>\n";
    echo 
"<BR>oder bei: <A HREF=http://hodoku.sourceforge.net/de/techniques.php</A>http://hodoku.sourceforge.net/de/techniques.php\n";
}

function 
microtime_float() {
    list(
$usec$sec) = explode(" "microtime());
    
$time = (float)$usec + (float)$sec;
    return 
$time;
}

function 
durchgestrichen($z$string) {
    
// ereg_replace is deprecated in PHP 5.3.0, removed in PHP 6.0.0
    
return preg_replace("/($z)/""[\$1]"$string);
}

function 
addiere_reste($r1$r2) {
    
$r12 $r1 $r2;
    
$r "";
    for (
$k 1$k <= 9$k++) {
        if (
strpos($r12"$k") !== FALSE$r $r "$k";
    }
    return 
$r;
}

function 
sichtbar($index1$index2) {
    
$row1 row_number($index1);
    
$row2 row_number($index2);
    
$col1 col_number($index1);
    
$col2 col_number($index2);
    
$box1r box_number_r($index1);
    
$box2r box_number_r($index2);
    
$box1c box_number_c($index1);
    
$box2c box_number_c($index2);
    if (
$row1 == $row2 || $col1 == $col2 || ($box1r == $box2r && $box1c == $box2c)) return 1;
    else return 
0;
}

function 
check_common($index1$index2) {
    
// Alle Felder zu erstem Index
    
$row1 row($index1);
    
$col1 col($index1);
    
$box1 box($index1);
    
// Alle Felder zu zweitem Index
    
$row2 row($index2);
    
$col2 col($index2);
    
$box2 box($index2);
    
// Alle gemeinsamen Felder
    /*
    $both = array();
    foreach($row2 as $value) {
        if (in_array($value, $row1) || in_array($value, $col1) || in_array($value, $box1)) {
            if (!in_array($value, $both)) $both[] = $value;
        }
    }
    foreach($col2 as $value) {
        if (in_array($value, $row1) || in_array($value, $col1) || in_array($value, $box1)) {
            if (!in_array($value, $both)) $both[] = $value;
        }
    }
    foreach($box2 as $value) {
        if (in_array($value, $row1) || in_array($value, $col1) || in_array($value, $box1)) {
            if (!in_array($value, $both)) $both[] = $value;
        }
    }
    sort ($both);
    */
    // Mit Prozeduren
    
$all1 array_merge($row1$col1$box1);
    
$all1 array_unique(array_values($all1));
    
$all2 array_merge($row2$col2$box2);
    
$all2 array_unique(array_values($all2));
    
// Alle gemeinsamen Felder
    
$both array_intersect($all1$all2);
    
$both array_values($both);
    
sort($both);

    return 
$both;
}

// Definition der Markierungswerte:
// d.h. "Spezielle" Zahlen nur aus optischen Gruenden, damit schneller erkennbar
// 32767: Nicht mehr besetzbar durch die aktuelle Zahl (da schon in gleicher Zeile, Spalte oder Box)
//  9999: Zwei oder drei Alternativen fuer die aktuelle Zahl in einer Zeile oder Spalte einer Box
// 20000: Wegen 9999 in der gleichen Zeile oder Spalte (andere Box) nicht besetzbar durch die aktuelle Zahl

function markiere_32767($sudoku_array$zahl) {
    
// Markiere alle mit der laufenden Zahl erreichbaren Felder (mit 32767)
    
$sudoku_array_copy $sudoku_array;
    for (
$index 0$index 81$index++) {
        
$field_value $sudoku_array[$index];
        if (
$field_value == $zahl) {
            foreach (
row($index) as $value) {
                if (
$sudoku_array[$value] == 0$sudoku_array_copy[$value] = 32767;
            }
            foreach (
col($index) as $value) {
                if (
$sudoku_array[$value] == 0$sudoku_array_copy[$value] = 32767;
            }
            foreach (
box($index) as $value) {
                if (
$sudoku_array[$value] == 0$sudoku_array_copy[$value] = 32767;
            }
        }
    }
    return 
$sudoku_array_copy;
}

function 
markiere_alle($sudoku_array$zahl, &$info_text) {
    
// $info_text wird hier veraendert!
    // Drei Schritte:
    //   1. Markiere (mit 32767) nicht mehr besetzbare Felder
    //   2. Zaehle in allen Boxen echte freie Felder (mit 0)
    //   3. Setze Markierung (9999 und 20000) an bestimmte Stellen
  
    // 1. Markiere alle mit der laufenden Zahl erreichbaren Felder (mit 32767)
    
$sudoku_array_copy markiere_32767($sudoku_array$zahl);
  
    
// Loop ueber Schritte 2 und 3
    
$nochmal 1// Erzwinge Loop
    
while ($nochmal == 1) {
        
$nochmal 0;
        
// 2. Bestimme zuerst alle echten freien Felder (mit 0) in Boxen
        
$null_array = array();
        for (
$a 0$a 3$a++) {
        for (
$b 0$b 3$b++) {
            
$index_box 27*$a 3*$b;
               
            
// Speichere alle Positionen der 0-Werte in Array von Arrays
            
$null = array();
            foreach (
box($index_box) as $value) {
                
// Echte Null, also auch ungleich 32767 bzw. 20000
                
if ($sudoku_array_copy[$value] == 0$null[] = $value;
            }
            
$null_array[] = $null;
        }
        }
      
        
// 3. Setze 9999 fuer moegliche Stellen der Zahl innerhalb einer Box (in genau einer Zeile/Spalte)
        
$box 0;
        for (
$a 0$a 3$a++) {   // Stufe 1
        
for ($b 0$b 3$b++) {   // Stufe 2
            
$index_box 27*$a 3*$b;
            
$a_1 $a 1;
            
$b_1 $b 1;
       
            
$null $null_array[$box];
            if (
count($null) == || count($null) == 3) {
         
                
// Zwei oder drei Alternativen in einer Zeile
                
$row row_number($null[0]);
                if ((
count($null) == && $row == row_number($null[1])) ||
                        (
count($null) == && $row == row_number($null[1]) && $row == row_number($null[2]))) {
                    
// Markiere mit 9999 eine moegliche Stelle fuer Zahl (nur in Trefferbox), sonst 20000
                    
$box_c box_number_c($null[0]);
                    foreach (
row($null[0]) as $value) {
                        if (
$sudoku_array[$value] == && $sudoku_array_copy[$value] != 32767) {
                            if (
box_number_c($value) == $box_c$sudoku_array_copy[$value] = 9999;
                            else {
                                
$sudoku_array_copy[$value] = 20000;
                                
$row_1 $row 1;
                                
$text "In Box $a_1#$b_1 ist Zahl $zahl nur in Zeile $row_1 dieser Box m&ouml;glich";
                                if (!
in_array($text$info_text)) $info_text[] = $text;
                            }
                        }
                    }
                    
$nochmal 1;
                }
         
                
// Zwei oder drei Alternativen in einer Spalte
                
$col col_number($null[0]);
                if ((
count($null) == && $col == col_number($null[1])) ||
                        (
count($null) == && $col == col_number($null[1]) && $col == col_number($null[2]))) {
                    
// Markiere mit 9999 eine moegliche Stelle fuer Zahl (nur in Trefferbox), sonst 20000
                    
$box_r box_number_r($null[0]);
                    foreach (
col($null[0]) as $value) {
                        if (
$sudoku_array[$value] == && $sudoku_array_copy[$value] != 32767) {
                            if (
box_number_r($value) == $box_r$sudoku_array_copy[$value] = 9999;
                            else {
                                
$sudoku_array_copy[$value] = 20000;
                                
$col_1 $col 1;
                                
$text "In Box $a_1#$b_1 ist Zahl $zahl nur in Spalte $col_1 dieser Box m&ouml;glich";
                                if (!
in_array($text$info_text)) $info_text[] = $text;
                            }
                        }
                    }
                    
$nochmal 1;
                }
            }
            
$box++;
        }   
// Ende Stufe 2
        
}   // Ende Stufe 1
    
// Loop

    
return $sudoku_array_copy;
}

function 
teste_reste(&$sudoku_array, &$sudoku_array_color$sudoku_array_rest, &$last_index) {
    global 
$neuereste$anzahl$d_anzahl$e_anzahl$punkte$punkte_art$farbe_gruen$farbe_rot$farbe_blau$farbe_braun$farbe_lila$farbe_rotgelb;
  
    
$test 0;
    
$while 0;
    
// Suche einstellige, damit eindeutige Loesungen
    // Beispiel: Rest "5" => Eindeutiger Wert
    
while ($while == 0) {   // Stufe 1
        
$while 1// Nur einmal durchlaufen um mit break zu einem return zu kommen
        
for ($index 0$index 81$index++) {   // Stufe 2
            
$rest $sudoku_array_rest[$index];
            if (
strlen($rest) == 1) {
                
$sudoku_array[$index] = $rest;
                
$r_1 row_number($index) + 1;
                
$c_1 col_number($index) + 1;
                
$last_index $index;
                
$sudoku_array_color[$index] = "&gt;<FONT COLOR=$farbe_braun>$rest</FONT>&lt;";
                echo 
"<BR>D1 - Einzige M&ouml;glichkeit in Zeile $r_1 und Spalte $c_1: Zahl $rest\n";
                
$neuereste 1;
                
$punkte $punkte $punkte_art[4];
                
$d_anzahl++;
                
$anzahl++;
                
$test 1;
                break 
2;
            }
        }   
// Stufe 2
        
        // Suche eindeutige Moeglichkeiten (nur 1 Alternative):
        //   Zaehle in jeder Zeile, Spalte, Box, ob von allen Alternativen in dieser Zeile, Spalte, Box
        //   eine Zahl genau ein Mal vorkommt
        //   (z.B.: Reste "169","48","16","58","149" => "5" kommt nur ein Mal vor)
    
        // Einzig aufgetretene Alternativen in Zeilen
        
for ($r 0$r 9$r++) {   // Stufe 2
            
$index $r;
            
$r_1 $r 1;
            
// Jede Zahl
            
for ($z 1$z <= 9$z++) {   // Stufe 3
                
$last 0;
                
$anz 0;
                foreach (
row($index) as $value) {
                    if (
strlen($sudoku_array_rest[$value]) >= 1) {
                        if (
strpos($sudoku_array_rest[$value], "$z") !== FALSE) {
                            
$last $value;
                            
$anz++;
                        }
                    }
                }
                if (
$anz == 1) {
                    
$sudoku_array[$last] = $z;
                    
$c_1 col_number($last) + 1;
                    
$last_index $last;
                    
$sudoku_array_color[$last] = "&gt;<FONT COLOR=$farbe_lila>$z</FONT>&lt;";
                    echo 
"<BR>E1 - Einzige M&ouml;glichkeit f&uuml;r Zahl $z in Zeile $r_1: Spalte $c_1\n";
                    
$neuereste 1;
                    
$punkte $punkte $punkte_art[5];
                    
$e_anzahl++;
                    
$anzahl++;
                    
$test 1;
                    break 
3;
                }
            }   
// Stufe 3
        
}   // Stufe 2
    
        // Einzig aufgetretene Alternativen in Spalten
        
for ($c 0$c 9$c++) {   // Stufe 2
            
$index $c;
            
$c_1 $c 1;
            
// Jede Zahl
            
for ($z 1$z <= 9$z++) {   // Stufe 3
                
$last 0;
                
$anz 0;
                foreach (
col($index) as $value) {
                    if (
strlen($sudoku_array_rest[$value]) >= 1) {
                        if (
strpos($sudoku_array_rest[$value], "$z") !== FALSE) {
                            
$last $value;
                            
$anz++;
                        }
                    }
                }
                if (
$anz == 1) {
                    
$sudoku_array[$last] = $z;
                    
$r_1 row_number($last) + 1;
                    
$last_index $last;
                    
$sudoku_array_color[$last] = "&gt;<FONT COLOR=$farbe_lila>$z</FONT>&lt;";
                    echo 
"<BR>E2 - Einzige M&ouml;glichkeit f&uuml;r Zahl $z in Spalte $c_1: Zeile $r_1\n";
                    
$neuereste 1;
                    
$punkte $punkte $punkte_art[5];
                    
$e_anzahl++;
                    
$anzahl++;
                    
$test 1;
                    break 
3;
                }
            }   
// Stufe 3
        
}   // Stufe 2
    
        // Einzig aufgetretene Alternativen in Boxen
        // Alle Boxen starten bei der ersten Farbe: Einfacher formulierbar mit: foreach (frb(0) as $index) {
        
for ($a 0$a 3$a++) {   // Stufe 2
        
for ($b 0$b 3$b++) {   // Stufe 3
            
$index 27*$a 3*$b;
            
$a_1 $a 1;
            
$b_1 $b 1;
            
// Jede Zahl
            
for ($z 1$z <= 9$z++) {   // Stufe 4
                
$last 0;
                
$anz 0;
                foreach (
box($index) as $value) {
                    if (
strlen($sudoku_array_rest[$value]) >= 1) {
                        if (
strpos($sudoku_array_rest[$value], "$z") !== FALSE) {
                            
$last $value;
                            
$anz++;
                        }
                    }
                }
                if (
$anz == 1) {
                    
$sudoku_array[$last] = $z;
                    
$r_1 row_number($last) + 1;
                    
$c_1 col_number($last) + 1;
                    
$last_index $last;
                    
$sudoku_array_color[$last] = "&gt;<FONT COLOR=$farbe_lila>$z</FONT>&lt;";
                    echo 
"<BR>E3 - Einzige M&ouml;glichkeit f&uuml;r Zahl $z in Box $a_1#$b_1: Zeile $r_1 und Spalte $c_1\n";
                    
$neuereste 1;
                    
$punkte $punkte $punkte_art[5];
                    
$e_anzahl++;
                    
$anzahl++;
                    
$test 1;
                    break 
4;
                }
            }   
// Stufe 4
        
}   // Stufe 3
        
}   // Stufe 2
    
}   // Stufe 1
  
    
return $test;
}

function 
check_correctness($sudoku_array) {
    global 
$box_row$box_col;
  
    
// Test in Zeilen
    
$error 0;
    
// In Zeilen
    
for ($r 0$r 9$r++) {   // Stufe 1
        
$r_1 $r 1;
        
$index $r;
        
$gefunden = array();
        foreach (
row($index) as $value) {   // Stufe 2
            
$z $sudoku_array[$value];
            if (
$z != 0) {
                if (!
in_array($z$gefunden)) $gefunden[] = $z;
                else {
                    echo 
"<H2>Keine L&ouml;sung! Zahl $z mehr als einmal in Zeile $r_1!</H2>\n";
                    
$error 1;
                    break 
2;
                }
            }
        }   
// Stufe 2
    
}   // Stufe 1
   
    // Test in Spalten
    
for ($c 0$c 9$c++) {   // Stufe 1
        
$c_1 $c 1;
        
$index $c;
        
$gefunden = array();
        foreach (
col($index) as $value) {   // Stufe 2
            
$z $sudoku_array[$value];
            if (
$z != 0) {
                if (!
in_array($z$gefunden)) $gefunden[] = $z;
                else {
                    echo 
"<H2>Keine L&ouml;sung! Zahl $z mehr als einmal in Spalte $c_1!</H2>\n";
                    
$error 1;
                    break 
2;
                }
            }
        }   
// Stufe 2
    
}   // Stufe 1
   
    // Test in Boxen
    // Alle Boxen starten bei der ersten Farbe: Einfacher formulierbar mit: foreach (frb(0) as $index) {
    
for ($a 0$a 3$a++) {   // Stufe 1
    
for ($b 0$b 3$b++) {   // Stufe 2
        
$a_1 $a 1;
        
$b_1 $b 1;
        
$index 27*$a 3*$b;
        
$gefunden = array();
        foreach (
box($index) as $value) {   // Stufe 3
            
$z $sudoku_array[$value];
            if (
$z != 0) {
                if (!
in_array($z$gefunden)) $gefunden[] = $z;
                else {
                    
$box_name "$box_row[$a]$box_col[$b]";
                    echo 
"<H2>Keine L&ouml;sung! Zahl $z mehr als einmal in Box $a_1#$b_1 ($box_name)!</H2>\n";
                    
$error 1;
                    break 
3;
                }
            }
        }   
// Stufe 3
    
}   // Stufe 2
    
}   // Stufe 1

  
if ($error == 1) {
      
zwischen_ausgabe($sudoku_array, array());
  }
  
    return 
$error;
}

// Zwischen-Ausgabe
function zwischen_ausgabe($sudoku_array_xxxx$sudoku_array_rest) {
    global 
$anzahl$punkte;
  
    
// Eventuell keine Reste anzeigen
    
if ($sudoku_array_rest == array()) $rest_leer 1;
    else 
$rest_leer 0;

    echo 
"<P>";
    echo 
"<TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
$index 0;
    for (
$r 0$r 9$r++) {
        echo 
"<TR>\n";
        for (
$c 0$c 9$c++) {
            
$field_name "a$index";
            
$field_value $sudoku_array_xxxx[$index];
  
            if (
$field_value === 0) {
                
$rest $sudoku_array_rest[$index];
            }
            else {
                
$rest "&nbsp;";
            }
  
            
// Wichtig: === wegen Strings im Feld
            
if ($field_value === 0) {
                if (
$rest == ""$rest "&nbsp;";
                if (
$rest == "123456789"$rest ""// statt: $rest = "1..9"
                
if ($rest_leer == 1) echo "<TD><INPUT TYPE=TEXT NAME=$field_name VALUE=\"\" SIZE=1 MAXLENGTH=1></TD>\n";
                else echo 
"<TD><INPUT TYPE=TEXT NAME=$field_name VALUE=\"\" SIZE=1 MAXLENGTH=1><BR>$rest</TD>\n";
            }
            else {
                if (
$rest_leer == 1) {
                    if (
substr($field_value04) == "&gt;") {
                        
// Markierung nicht Bold
                        
$innen substr($field_value4, -4);
                        echo 
"<TD>&gt;<B>$innen</B>&lt;</TD>\n";
                    }
                    else {
                        echo 
"<TD><B>$field_value</B></TD>\n";
                    }
                }
                else {
                    echo 
"<TD><B>$field_value</B><BR>$rest</TD>\n";
                }
            }
            if (
$c == || $c == 5) echo "<TD>|<BR>|</TD>\n";
            
$index++;
        }
        echo 
"</TR>\n";
        if (
$r == || $r == 5) echo "<TR><TD COLSPAN=11><HR></TD></TR>\n";
    }
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    if (
$anzahl != "") echo "<P>Anzahl Zahlen: $anzahl, Punkte: $punkte\n";
    echo 
"<BR>\n";
}

$php_self $_SERVER['PHP_SELF'];

// Initialisierungen
// Timezone (notwendig seit Version 5.1)
// date_default_timezone_set('Europe/Berlin');

// Maximale Goldene Ketten-Anzahl (Bisherige Maxima aller 21000 geloesten Sudokus: 1824=>2266=>2770, 1458=>2470=>4130)
$max_kette 10000;
// X-Wing ausschaltbar (bei xwing = 0)
$xwing 1;
// Fuer Loop ueber alle 9 Zahlen
$zahlen = array(123456789);
// Werte-Punkte - spaeter vom User setzbar
// Feld 0: Schwarz: Vorhandene Ausgangszahlen
// Feld 1: Gruen: Einzige Position in Box und Zeile/Spalte (neu: Zeile/Spalte doppelt so viel wert)
// Feld 2: Rot: Einzige Position in Zeile/Spalte/Box wegen nicht moeglichen anderen Positionen
// Feld 3: Blau: Einstellige, damit eindeutige Loesungen
// Feld 4: Braun: Loesung durch weitergehendes Ausduennen mit einstelligem Rest
// Feld 5: Lila: Loesung durch weitergehendes Ausduennen mit einzig auftretendem Rest
// $punkte_art = array(0, 1, 6, 8, 2, 4);
$punkte_art = array(014614);
// Extra-Punkte - spaeter vom User setzbar
// Bemerkung: Die Reihenfolge im Array entspricht nicht der Reihenfolge im Programm (Umstellung)
// Feld 0: Dummy
// Feld 1: Box-Test der Reste in einer Zeile oder Spalte
// Feld 2: Zeilen-/Spalten-Test der Reste innerhalb einer Box
// Feld 3: Faktor * N (von N-Tupel)
// Feld 4: X-Wing
// Feld 5: Faktor * Laenge der Kette
$ausduenn_punkte = array(0462103);
// Box-Bezeichnung
$box_row = array("O""M""U");
$box_col = array("L""M""R");
// Fuer N-Tupel-Texte
$tupel = array("0""0""2-Tupel (Doppel)""3-Tupel (Tripel)""4-Tupel (Quadrupel)""5-Tupel (Pentupel)""6-Tupel""7-Tupel");
// Farben fuer Methoden 1 - 5
$farbe_gruen "\"#00CC00\"";
$farbe_rot "\"#FF0000\"";
$farbe_blau "\"#0000FF\"";
$farbe_braun "\"#FFAA00\"";
$farbe_lila "\"#CC00FF\"";
// Bei Ausduenneng: Reste-Markierung
$farbe_rotgelb "\"#FF2200\"";

// (HIDDEN-)Parameter lesen
if (array_key_exists('sudoku'$_POST)) $sudoku $_POST['sudoku']; else $sudoku "";
if (
array_key_exists('status'$_POST)) $status $_POST['status']; else $status "";
if (
array_key_exists('punkte'$_POST)) $punkte $_POST['punkte']; else $punkte 0;
// if (array_key_exists('STANDARD', $_POST)) $STANDARD = $_POST['STANDARD']; else $STANDARD = "";

// Query-String lesen
$query $_SERVER['QUERY_STRING'];

// Drei Anfangsfaelle: Leeres Sudoku mit Eintragungen; Vorgegebenes Sudoku (Query-String); Verzweigung

// Normalfall: Leeres Sudoku mit Eintragungen: nach Werten fragen
if (($status === "" && $query === "") || $query == "000000000000000000000000000000000000000000000000000000000000000000000000000000000_0") {
  
    
$status 0;
  
    echo 
"<H3>Geben Sie die Ausgangszahlen ein (1..9)</H3>\n";

    
// Eingabe
    
echo "<FORM METHOD=POST NAME=sudoku ACTION=\"$php_self\">\n";
    echo 
"<INPUT TYPE=HIDDEN NAME=status VALUE=$status>\n";
    
// Fuer TAB-Text
    
echo "<TABLE BORDER=0>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
$index 0;
    for (
$r 0$r 9$r++) {
        echo 
"<TR>\n";
        for (
$c 0$c 9$c++) {
            
$field_name "a$index";
            echo 
"<TD><INPUT TYPE=TEXT NAME=$field_name VALUE=\"\" SIZE=1 MAXLENGTH=1></TD>\n";

            if (
$c == || $c == 5) echo "<TD>|<BR>|</TD>\n";
            
$index++;
        }
        echo 
"</TR>\n";
        if (
$r == || $r == 5) echo "<TR><TD COLSPAN=11><HR></TD></TR>\n";
    }
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"</TD><TD VALIGN=\"TOP\">&nbsp; PS: Sie k&ouml;nnen mit der TAB-Taste von Feld zu Feld springen<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ohne die Maus zu benutzen :-)\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
  
    echo 
"<SCRIPT TYPE=\"text/javascript\">\n";
    echo 
"document.sudoku.a0.focus();\n";
    echo 
"</SCRIPT>\n";

    echo 
"<P>";

    
// echo "<INPUT TYPE=SUBMIT NAME=SUBMIT VALUE=\"Go!\">\n";
    // Wenn man im Safari zweimal die Enter/Return-Taste drueckt, wird das Formular abgeschickt
    // Bei Firefox und Internet Explorer reicht einmal ...
    
echo "<INPUT TYPE=SUBMIT VALUE=\"Go!\">\n";
    echo 
"</FORM>\n";
  
    echo 
"<P><HR><P>";
  
    
erklaerung();
}
// Vorgegebenes Sudoku - mit Frage nach Test-Typ
elseif (substr($query82) === "0") {
    
// (int) wichtig wegen spaeterem ===
    
for ($k 0$k 81$k++) $sudoku_array[$k] = (int) substr($query$k1);
    
$status 0;
  
    echo 
"<H3>Vorgegebenes Beispiel</H3>";
    echo 
"<FORM METHOD=POST ACTION=\"$php_self\">\n";
    echo 
"<INPUT TYPE=HIDDEN NAME=status VALUE=$status>\n";
    
// zwischen_ausgabe($sudoku_array, array());
    
echo "<TABLE BORDER=1 CELLSPACING=4 CELLPADDING=4>\n";
    echo 
"<TR><TD>\n";
    echo 
"<TABLE CELLSPACING=0 CELLPADDING=4>\n";
    
$index 0;
    for (
$r 0$r 9$r++) {
        echo 
"<TR>\n";
        for (
$c 0$c 9$c++) {
            
$field_name "a$index";
            
$field_value $sudoku_array[$index];

            
// Wichtig: === wegen Strings im Feld
            
if ($field_value === 0) {
                echo 
"<TD><INPUT TYPE=TEXT NAME=$field_name VALUE=\"\" SIZE=1 MAXLENGTH=1></TD>\n";
            }
            else {
                echo 
"<TD><B><INPUT TYPE=TEXT NAME=$field_name VALUE=\"$field_value\" SIZE=1 MAXLENGTH=1></B></TD>\n";
            }
            if (
$c == || $c == 5) echo "<TD>|<BR>|</TD>\n";
            
$index++;
        }
        echo 
"</TR>\n";
        if (
$r == || $r == 5) echo "<TR><TD COLSPAN=11><HR></TD></TR>\n";
    }
    echo 
"</TABLE>\n";
    echo 
"</TD></TR>\n";
    echo 
"</TABLE>\n";
    echo 
"<P>";

    echo 
"<INPUT TYPE=SUBMIT VALUE=\"Go!\">\n";
    echo 
"</FORM>\n";
  
    echo 
"<P><HR><P>";
    
// erklaerung();
}
else {
    
// Hauptteil (eigentliche Abarbeitung)
    // Statt: $sudoku_array = array(0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,  ...  0,0,0,0,0,0,0,0,0);
    
$sudoku_array array_fill(0810);
  
    
// Beginn Uebertragung und Berechnungen
  
    // Vorgegebenes Sudoku (Query-String)
    
if ($query != "") {
        if (
substr($query82) == "X") {
      
$xwing 0;
      
$status 0;
    }
    else {
      
$xwing 1;
            
$status = (int) substr($query82);
    }
        
// (int) wichtig wegen spaeterem ===
        
for ($k 0$k 81$k++) $sudoku_array[$k] = (int) substr($query$k1);
    }
    
// Leeres Sudoku mit Eintragungen; bzw. Verzweigung
    
else {
        
// Werte aus Hidden-Parameter (bei Verzweigung)
        
if ($sudoku != "") {
            
// (int) wichtig wegen spaeterem ===
            
for ($k 0$k 81$k++) $sudoku_array[$k] = (int) substr($sudoku$k1);
        }
        else {
            
$status 0;
        }
        
// Aus Formblatt Parameter uebertragen (in beiden Faellen)
        
for ($index 0$index 81$index++) {
            
$string_name "a$index";
            if (
array_key_exists("$string_name"$_POST)) {
                
$orig $_POST["$string_name"];
                
// Abfangen von Eingabefehlern
                
if ($orig != "") {
                    
$name = (int) $orig;
                    if (
$name || $name 9) {
                        
$index_1 $index 1;
                        
$r_1 row_number($index) + 1;
                        
$c_1 col_number($index) + 1;
                        echo 
"<H3><FONT COLOR=$farbe_rot>Fehler in Zeile $r_1 und Spalte $c_1: Keine Zahl zwischen 1 und 9 ($orig)</FONT></H3>\n";
                        
$sudoku_array[$index] = 0;
                    }
                    else {
                        
$sudoku_array[$index] = $name;
                    }
                }
            }
        }  
// for
    
}
    
// TEST
    /*
    $sudoku_array = array(0,1,2,7,6,0,8,5,3, 7,0,0,0,2,5,1,9,6, 0,6,5,3,0,0,2,7,4,
                                                0,2,7,1,0,6,9,8,5, 6,5,9,0,7,0,0,2,1, 1,0,8,9,5,2,0,6,7,
                                                5,9,0,2,0,7,6,4,8, 0,0,6,5,0,0,7,1,2, 2,7,0,6,8,0,5,3,9);
                                                */

    
    
$time_anf microtime_float();
    
// Ausgangszahlen zaehlen
    
$anzahl 0;
    for (
$index 0$index 81$index++) {
        if (
$sudoku_array[$index] != 0$anzahl++;
    }
    
$anzahl_anfangs $anzahl;
  
    
// Statt: $sudoku_array_rest = array("123456789","123456789", ... "123456789","123456789");
    
$sudoku_array_rest array_fill(081"123456789");
    
$ausduennen false;
  
    
// Wegen farbiger Ausgabe
    
$sudoku_array_color $sudoku_array;
  
    if (
$status == 0$punkte 0;   // sonst Uebernahme vom vorherigen Aufruf
    
$simple 0;
    
$a_anzahl 0;
    
$b_anzahl 0;
    
$c_anzahl 0;
    
$d_anzahl 0;
    
$e_anzahl 0;
    
$ausduenn_schritte 0;
    
$ausduenn_maximum 0;
    
$ausduenn_felder 0;
    
$ntupel_anzahl 0;
    
$ntupel_max 0;
    
$xwing_anzahl 0;
    
$golden_anzahl 0;
    
$golden_maxlen 0;
    
    
// Darstellung ohne Reste
    
echo "<H1><FONT COLOR=$farbe_rot>Gew&auml;hltes Beispiel</FONT></H1>\n";
    
zwischen_ausgabe($sudoku_array, array());
  
    
$error check_correctness($sudoku_array);
    
    
// Gesamtloop
    
while ($anzahl 81 && $error == 0) {   // Stufe 1
        // zwischen_ausgabe($sudoku_array_color, array());
      
        
$anzahl_vorher_grosse_loop $anzahl 1// Erzwinge Loop
            
while ($anzahl_vorher_grosse_loop $anzahl) {   // Stufe 2
            
$anzahl_vorher_grosse_loop $anzahl;
      
            
// Fuer nur einmalige Ausgabe der Info-Texte
            
$info_text = array();
      
            
// Einfach und ohne Punkte: Suche letzte noch fehlende Zahl in Zeile
            
for ($r 0$r 9$r++) {   // Stufe 3
                
$index_row $r;
                
$r_1 $r 1;
          
                
// Speichere alle Positionen der 0-Werte in Array
                
$not_pos = array();
                
$val = array();
                foreach (
row($index_row) as $value) {
                    if (
$sudoku_array[$value] == 0$not_pos[] = $value;
                    else 
$val[] = $sudoku_array[$value];
                }

                
// Nur eine fehlende Zahl
                
if (count($not_pos) == 1) {
                    
$zahl 0;
                    foreach (
$zahlen as $wert) {
                        if (!
in_array($wert$val)) $zahl $wert;
                    }
                    
$current $not_pos[0];
                    
$c_1 col_number($current) + 1;
                    
                    
$last_index $current;
                    
$sudoku_array[$current] = $zahl;
                    
$sudoku_array_copy[$current] = $zahl;
                    
$sudoku_array_color[$current] = "&gt;<FONT COLOR=$farbe_gruen>$zahl</FONT>&lt;";
                    echo 
"<BR>A1 - Letzte Position f&uuml;r Zahl $zahl in Zeile $r_1: Spalte $c_1\n";
          
                    
// Wegen zwangsweiser Setzung einer Zahl kann ein Widerspruch entstanden sein
                    
$error check_correctness($sudoku_array);
                    if (
$error == 1) break 3;
          
                    
// 0 Punkte, da letzte Zahl
                    
$punkte $punkte 0;
                    
$a_anzahl++;
             
                    
$anzahl++;
                    if (
$anzahl == 81) break 3;
                    
$sudoku_array_copy markiere_32767($sudoku_array$zahl);
                    
zwischen_ausgabe($sudoku_array_color, array());
                    
// Markierung weg werfen
                    
$sudoku_array_color[$last_index] = substr($sudoku_array_color[$last_index], 4, -4);
                    continue 
3;
                }
            }   
// Stufe 3
      
            // Einfach und ohne Punkte: Suche letzte noch fehlende Zahl in Spalte
            
for ($c 0$c 9$c++) {   // Stufe 3
                
$index_col $c;
                
$c_1 $c 1;
          
                
// Speichere alle Positionen der 0-Werte in Array
                
$not_pos = array();
                
$val = array();
                foreach (
col($index_col) as $value) {
                    if (
$sudoku_array[$value] == 0$not_pos[] = $value;
                    else 
$val[] = $sudoku_array[$value];
                }
        
                
// Nur eine fehlende Zahl
                
if (count($not_pos) == 1) {
                    
$zahl 0;
                    foreach (
$zahlen as $wert) {
                        if (!
in_array($wert$val)) $zahl $wert;
                    }
                    
$current $not_pos[0];
                    
$r_1 row_number($current) + 1;
                    
                    
$last_index $current;
                    
$sudoku_array[$current] = $zahl;
                    
$sudoku_array_copy[$current] = $zahl;
                    
$sudoku_array_color[$current] = "&gt;<FONT COLOR=$farbe_gruen>$zahl</FONT>&lt;";        
                    echo 
"<BR>A2 - Letzte Position f&uuml;r Zahl $zahl in Spalte $c_1: Zeile $r_1\n";
          
                    
// Wegen zwangsweiser Setzung einer Zahl kann ein Widerspruch entstanden sein
                    
$error check_correctness($sudoku_array);
                    if (
$error == 1) break 3;
          
                    
// 0 Punkte, da letzte Zahl
                    
$punkte $punkte 0;
                    
$a_anzahl++;
             
                    
$anzahl++;
                    if (
$anzahl == 81) break 3;
                    
$sudoku_array_copy markiere_32767($sudoku_array$zahl);
                    
zwischen_ausgabe($sudoku_array_color, array());
                    
// Markierung weg werfen
                    
$sudoku_array_color[$last_index] = substr($sudoku_array_color[$last_index], 4, -4);
                    continue 
3;
                }
            }   
// Stufe 3
      
            // Einfach und ohne Punkte: Suche letzte noch fehlende Zahl in Box
            
for ($a 0$a 3$a++) {   // Stufe 3
            
for ($b 0$b 3$b++) {   // Stufe 4
                
$index_box 27*$a 3*$b;
                
$a_1 $a 1;
                
$b_1 $b 1;
          
                
// Speichere alle Positionen der 0-Werte in Array
                
$not_pos = array();
                
$val = array();
                foreach (
box($index_box) as $value) {
                    if (
$sudoku_array[$value] == 0$not_pos[] = $value;
                    else 
$val[] = $sudoku_array[$value];
                }
        
                
// Nur eine fehlende Zahl
                
if (count($not_pos) == 1) {
                    
$zahl 0;
                    foreach (
$zahlen as $wert) {
                        if (!
in_array($wert$val)) $zahl $wert;
                    }
                    
$current $not_pos[0];
                    
$r_1 row_number($current) + 1;
                    
$c_1 col_number($current) + 1;
                    
$box_name "$box_row[$a]$box_col[$b]";
                    
                    
$last_index $current;
                    
$sudoku_array[$current] = $zahl;
                    
$sudoku_array_copy[$current] = $zahl;
                    
$sudoku_array_color[$current] = "&gt;<FONT COLOR=$farbe_gruen>$zahl</FONT>&lt;";
                    echo 
"<BR>A3 - Letzte Position f&uuml;r Zahl $zahl in Box $a_1#$b_1 ($box_name): Zeile $r_1 und Spalte $c_1\n";
          
                    
// Wegen zwangsweiser Setzung einer Zahl kann ein Widerspruch entstanden sein
                    
$error check_correctness($sudoku_array);
                    if (
$error == 1) break 4;
          
                    
// 0 Punkte, da letzte Zahl
                    
$punkte $punkte 0;
                    
$a_anzahl++;
             
                    
$anzahl++;
                    if (
$anzahl == 81) break 4;
                    
$sudoku_array_copy markiere_32767($sudoku_array$zahl);
                    
zwischen_ausgabe($sudoku_array_color, array());
                    
// Markierung weg werfen
                    
$sudoku_array_color[$last_index] = substr($sudoku_array_color[$last_index], 4, -4);
                    continue 
4;
                }
            }   
// Stufe 4
            
}   // Stufe 3
      
            // Grosse Loop ueber alle Zahlen
            
foreach ($zahlen as $zahl) {   // Stufe 3
                
$eventuell_ausgabe 0;
        
                
// Markiere mit 32767
                
$sudoku_array_copy markiere_32767($sudoku_array$zahl);
         
                
// Einfache Abfrage, getrennt fuer Zeilen, Spalten, Boxen => Jetzt nur Boxen
                
$anzahl_vorher $anzahl 1// Erzwinge Loop
                
while ($anzahl_vorher $anzahl) {   // Stufe 4
                    
$anzahl_vorher $anzahl;

                    
// Suche einzelnes freies Feld in Boxen (echte 0)
                    
for ($a 0$a 3$a++) {   // Stufe 5
                    
for ($b 0$b 3$b++) {   // Stufe 6
                        
$index_box 27*$a 3*$b;
                        
$a_1 $a 1;
                        
$b_1 $b 1;
            
                        
// Speichere alle Positionen der 0-Werte in Array
                        
$null = array();
                        foreach (
box($index_box) as $value) {
                            if (
$sudoku_array_copy[$value] == 0$null[] = $value;
                        }
            
                        if (
count($null) == 1) {
                            
$current $null[0];
                            
$r_1 row_number($current) + 1;
                            
$c_1 col_number($current) + 1;
                            
$box_name "$box_row[$a]$box_col[$b]";
                            
                            
$last_index $current;
                            
$sudoku_array[$current] = $zahl;
                            
$sudoku_array_copy[$current] = $zahl;
                            
$sudoku_array_color[$current] = "&gt;<FONT COLOR=$farbe_gruen>$zahl</FONT>&lt;";
              
              
// Ist nie letzte Zahl
                            
echo "<BR>A3 - Einzige Position f&uuml;r Zahl $zahl in Box $a_1#$b_1 ($box_name): Zeile $r_1 und Spalte $c_1\n";
                            
$punkte $punkte $punkte_art[1];
                            
$a_anzahl++;
               
                            
$anzahl++;
                            if (
$anzahl == 81) break 6;
                            
// Suche mehrere auf einmal
                            
$eventuell_ausgabe++;
                            
$sudoku_array_copy markiere_32767($sudoku_array$zahl);
                        }
                    }   
// Stufe 6
                    
}   // Stufe 5
                
}   // Stufe 4
                // Ende einfache Abfrage
        
                
if ($eventuell_ausgabe != 0) {
                    
zwischen_ausgabe($sudoku_array_color, array());
                    
// Markierungen weg werfen
                    
for ($m 0$m 81$m++) { 
                        if (
strpos($sudoku_array_color[$m], "&lt;") > 0$sudoku_array_color[$m] = substr($sudoku_array_color[$m], 4, -4);
                    }
                    continue 
3;
                }
            }   
// Stufe 3
          
            // Grosse Loop ueber alle Zahlen
            
foreach ($zahlen as $zahl) {   // Stufe 3
              
                // Markiere mit 32767
                
$sudoku_array_copy markiere_32767($sudoku_array$zahl);
         
                
// Einfache Abfrage, getrennt fuer Zeilen, Spalten, Boxen => Jetzt nur Zeilen und Spalten
                
$anzahl_vorher $anzahl 1// Erzwinge Loop
                
while ($anzahl_vorher $anzahl) {   // Stufe 4
                    
$anzahl_vorher $anzahl;
           
                    
// Suche einzelnes freies Feld in Zeilen (echte 0)
                    
for ($r 0$r 9$r++) {   // Stufe 5
                        
$index_row $r;
                        
$r_1 $r 1;
            
                        
// Speichere alle Positionen der 0-Werte in Array
                        
$null = array();
                        foreach (
row($index_row) as $value) {
                            if (
$sudoku_array_copy[$value] == 0$null[] = $value;
                        }
            
                        if (
count($null) == 1) {
                            
$current $null[0];
                            
$c_1 col_number($current) + 1;
                            
                            
$last_index $current;
                            
$sudoku_array[$current] = $zahl;
                            
$sudoku_array_copy[$current] = $zahl;
                            
$sudoku_array_color[$current] = "&gt;<FONT COLOR=$farbe_gruen>$zahl</FONT>&lt;";
              
                            
// Ist nie letzte Zahl
                            
echo "<BR>A1 - Einzige Position f&uuml;r Zahl $zahl in Zeile $r_1: Spalte $c_1\n";
                            
$punkte $punkte 2*$punkte_art[1];
                            
$a_anzahl++;
               
                            
$anzahl++;
                            if (
$anzahl == 81) break 5;
                            
$sudoku_array_copy markiere_32767($sudoku_array$zahl);
                            
zwischen_ausgabe($sudoku_array_color, array());
                            
// Markierung weg werfen
                            
$sudoku_array_color[$last_index] = substr($sudoku_array_color[$last_index], 4, -4);
                            continue 
5;
                        }
                    }   
// Stufe 5
                
}   // Stufe 4
        
                
$anzahl_vorher $anzahl 1// Erzwinge Loop
                
while ($anzahl_vorher $anzahl) {   // Stufe 4
                    
$anzahl_vorher $anzahl;
          
                    
// Suche einzelnes freies Feld in Spalten (echte 0)
                    
for ($c 0$c 9$c++) {   // Stufe 5
                        
$index_col $c;
                        
$c_1 $c 1;
            
                        
// Speichere alle Positionen der 0-Werte in Array
                        
$null = array();
                        foreach (
col($index_col) as $value) {
                            if (
$sudoku_array_copy[$value] == 0$null[] = $value;
                        }
            
                        if (
count($null) == 1) {
                            
$current $null[0];
                            
$r_1 row_number($current) + 1;
                            
              
$last_index $current;
              
$sudoku_array[$current] = $zahl;
                            
$sudoku_array_copy[$current] = $zahl;
                            
$sudoku_array_color[$current] = "&gt;<FONT COLOR=$farbe_gruen>$zahl</FONT>&lt;";
              
                            
// Ist nie letzte Zahl
                            
echo "<BR>A2 - Einzige Position f&uuml;r Zahl $zahl in Spalte $c_1: Zeile $r_1\n";
                            
$punkte $punkte 2*$punkte_art[1];
                            
$a_anzahl++;
               
                            
$anzahl++;
                            if (
$anzahl == 81) break 5;
                            
$sudoku_array_copy markiere_32767($sudoku_array$zahl);
                            
zwischen_ausgabe($sudoku_array_color, array());
                            
// Markierung weg werfen
                            
$sudoku_array_color[$last_index] = substr($sudoku_array_color[$last_index], 4, -4);
                            continue 
5;
                        }
                    }   
// Stufe 5
                
}   // Stufe 4
        
                // Ende einfache Abfrage
            
}   // Stufe 3
            // Ende Grosse Loop ueber alle Zahlen
      
            // Grosse Loop ueber alle Zahlen
            
foreach ($zahlen as $zahl) {   // Stufe 3
           
                // Markiere mit 32767, 9999 und 20000 wegen Paaren und Tripeln in einer Zeile/Spalte einer Box
                
$sudoku_array_copy markiere_alle($sudoku_array$zahl$info_text);
                 
                
// Analyse der Markierungen fuer Zeilen
                
$anzahl_vorher $anzahl 1// Erzwinge Loop
                
while ($anzahl_vorher $anzahl) {   // Stufe 4
                    
$anzahl_vorher $anzahl;
          
                    
// Suche einzelnes freies Feld in Zeilen
                    
for ($r 0$r 9$r++) {   // Stufe 5
                        
$index_row $r;
                        
$r_1 $r 1;
            
                        
// Speichere alle Positionen der 0-Werte (0 oder 9999) und 20000-Werte in Array
                        
$null = array();
                        
$anz_20000 = array();
                        foreach (
row($index_row) as $value) {
                            if (
$sudoku_array_copy[$value] == || $sudoku_array_copy[$value] == 9999$null[] = $value;
                            if (
$sudoku_array_copy[$value] == 20000$anz_20000[] = $value;
                        }
            
                        if (
count($null) == && count($anz_20000) > 0) {
                            
$current $null[0];
                            
                            
// Suche Info-Text
                            
$text "";
                            foreach (
$info_text as $value) {
                                if (
strpos($value"Zahl $zahl") > 0$text .= ", und: " $value;
                            }
                            
$teil_text substr($text7);
                            
$c_1 col_number($current) + 1;
                                           
              
$sudoku_array[$current] = $zahl;
                            
$sudoku_array_copy[$current] = $zahl;
              
$last_index $current;
                            
$sudoku_array_color[$current] = "&gt;<FONT COLOR=$farbe_rot>$zahl</FONT>&lt;";
                            echo 
"<BR>B1 - Wegen: $teil_text: Einzige Position f&uuml;r Zahl $zahl der Zeile $r_1 in Spalte $c_1 gefunden\n";
                 
                            
$punkte $punkte $punkte_art[2];
                            
$b_anzahl++;
               
                            
$anzahl++;
                            if (
$anzahl == 81) break 5;
                            
$sudoku_array_copy markiere_alle($sudoku_array$zahl$info_text);
                            
zwischen_ausgabe($sudoku_array_color, array());
                            
// Markierung weg werfen
                            
$sudoku_array_color[$last_index] = substr($sudoku_array_color[$last_index], 4, -4);
                            continue 
5;
                        }
                    }   
// Stufe 5
                
}   // Stufe 4
        
                // Analyse fuer Spalten
                
$anzahl_vorher $anzahl 1// Erzwinge Loop
                
while ($anzahl_vorher $anzahl) {   // Stufe 4
                    
$anzahl_vorher $anzahl;
          
                    
// Suche einzelnes freies Feld in Spalten
                    
for ($c 0$c 9$c++) {   // Stufe 5
                        
$index_col $c;
                        
$c_1 $c 1;
            
                        
// Speichere alle Positionen der 0-Werte (0 oder 9999) und 20000-Werte in Array
                        
$null = array();
                        
$anz_20000 = array();
                        foreach (
col($index_col) as $value) {
                            if (
$sudoku_array_copy[$value] == || $sudoku_array_copy[$value] == 9999$null[] = $value;
                            if (
$sudoku_array_copy[$value] == 20000$anz_20000[] = $value;
                        }
            
                        if (
count($null) == && count($anz_20000) > 0) {
                            
$current $null[0];
                            
                            
// Suche Info-Text
                            
$text "";
                            foreach (
$info_text as $value) {
                                if (
strpos($value"Zahl $zahl") > 0$text .= ", und: " $value;
                            }
                            
$teil_text substr($text7);
                            
$r_1 row_number($current) + 1;
                
              
$sudoku_array[$current] = $zahl;
                            
$sudoku_array_copy[$current] = $zahl;
              
$last_index $current;
                            
$sudoku_array_color[$current] = "&gt;<FONT COLOR=$farbe_rot>$zahl</FONT>&lt;";
                            echo 
"<BR>B2 - Wegen: $teil_text: Einzige Position f&uuml;r Zahl $zahl der Spalte $c_1 in Zeile $r_1 gefunden\n";
               
                            
$punkte $punkte $punkte_art[2];
                            
$b_anzahl++;
               
                            
$anzahl++;
                            if (
$anzahl == 81) break 5;
                            
$sudoku_array_copy markiere_alle($sudoku_array$zahl$info_text);
                            
zwischen_ausgabe($sudoku_array_color, array());
                            
// Markierung weg werfen
                            
$sudoku_array_color[$last_index] = substr($sudoku_array_color[$last_index], 4, -4);
                            continue 
5;
                        }
                    }   
// Stufe 5
                
}   // Stufe 4
        
                // Analyse fuer Boxen
                
$anzahl_vorher $anzahl 1// Erzwinge Loop
                
while ($anzahl_vorher $anzahl) {   // Stufe 4
                    
$anzahl_vorher $anzahl;
          
                    
// Suche einzelnes freies Feld in Boxen
                    
for ($a 0$a 3$a++) {   // Stufe 5
                    
for ($b 0$b 3$b++) {   // Stufe 6
                        
$a_1 $a 1;
                        
$b_1 $b 1;
                        
$index_box 27*$a 3*$b;
            
                        
// Speichere alle Positionen der 0-Werte (0 oder 9999) und 20000-Werte in Array
                        
$null = array();
                        
$anz_20000 = array();
                        foreach (
box($index_box) as $value) {
                            if (
$sudoku_array_copy[$value] == || $sudoku_array_copy[$value] == 9999$null[] = $value;
                            if (
$sudoku_array_copy[$value] == 20000$anz_20000[] = $value;
                        }
            
                        if (
count($null) == && count($anz_20000) > 0) {
                            
$current $null[0];
                            
                            
// Suche Info-Text
                            
$text "";
                            foreach (
$info_text as $value) {
                                if (
strpos($value"Zahl $zahl") > 0$text .= ", und: " $value;
                            }
                            
$teil_text substr($text7);
                            
$r_1 row_number($current) + 1;
                            
$c_1 col_number($current) + 1;
                            
$box_name "$box_row[$a]$box_col[$b]";
                
              
$sudoku_array[$current] = $zahl;
                            
$sudoku_array_copy[$current] = $zahl;
              
$last_index $current;
                            
$sudoku_array_color[$current] = "&gt;<FONT COLOR=$farbe_rot>$zahl</FONT>&lt;";
                            echo 
"<BR>B3 - Wegen: $teil_text: Einzige Position f&uuml;r Zahl $zahl der Box $a_1#$b_1 ($box_name) in Zeile $r_1 und Spalte $c_1 gefunden\n";
               
                            
$punkte $punkte $punkte_art[2];
                            
$b_anzahl++;
               
                            
$anzahl++;
                            if (
$anzahl == 81) break 6;
                            
$sudoku_array_copy markiere_alle($sudoku_array$zahl$info_text);
                            
zwischen_ausgabe($sudoku_array_color, array());
                            
// Markierung weg werfen
                            
$sudoku_array_color[$last_index] = substr($sudoku_array_color[$last_index], 4, -4);
                            continue 
6;
                        }
                    }   
// Stufe 6
                    
}   // Stufe 5
                
}   // Stufe 4

                // Ende mit Markierungen und moeglichen Feldern
            
}   // Stufe 3
            // Ende Grosse Loop ueber alle Zahlen
      
            // Berechne die Reste: Gehe anfangs von 123456789 aus, danach von den aktuellen Resten
            // Streiche alle Zahlen aus, die in der gleichen Zeile, Spalte oder Box vorkommen
            
for ($index 0$index 81$index++) {   // Stufe 3
                
$field_value $sudoku_array[$index];
      
                if (
$field_value == 0) {
                    
// Streichen
                    
$rest $sudoku_array_rest[$index];
                    foreach (
row($index) as $value) {
                        
$pos $sudoku_array[$value];
                        
$rest str_replace($pos""$rest);
                    }
                    foreach (
col($index) as $value) {
                        
$pos $sudoku_array[$value];
                        
$rest str_replace($pos""$rest);
                    }
                    foreach (
box($index) as $value) {
                        
$pos $sudoku_array[$value];
                        
$rest str_replace($pos""$rest);
                    }
                }
                else {
                    
$rest "";
                }
                
$sudoku_array_rest[$index] = $rest;
            }   
// Stufe 3
            // Fuer naechste Ausgabe
            
$sudoku_array_rest_markiert $sudoku_array_rest;
      
            
// Einstellige, damit eindeutige Loesungen: Beispiel: Rest "5" => Eindeutiger Wert 5
            
for ($index 0$index 81$index++) {   // Stufe 3
                
$zahl $sudoku_array_rest[$index];
                if (
strlen($zahl) == 1) {
                    
$r_1 row_number($index) + 1;
                    
$c_1 col_number($index) + 1;
                    
                    
$sudoku_array[$index] = $zahl;
                    
$sudoku_array_rest[$index] = "";
          
                    
$last_index $index;
                    if (
$ausduennen == false) {
                        
$sudoku_array_color[$index] = "&gt;<FONT COLOR=$farbe_blau>$zahl</FONT>&lt;";
                        echo 
"<BR>C1 - Einzige M&ouml;glichkeit in Zeile $r_1 und Spalte $c_1: Zahl $zahl\n";
                        
$punkte $punkte $punkte_art[3];
                        
$c_anzahl++;
                    }
                    else {
                        
// Hier wird von den durch Ausduennen verkleinerten Resten ausgegangen, daher Methode D statt C
                        // Bemerkung: Ist manchmal auch direkt als C-Methode erkennbar
                        // Der Aufwand lohnt aber nicht, und es waeren unnoetig viele Punkte mehr (6 statt 1)!
                        // Markiere durchgestrichene Zahl (nur an der Trefferstelle)
                        
$rest_zahl str_replace($zahl""$sudoku_array_rest_markiert[$index]);
                        if (
$rest_zahl != "") {
                            
$sudoku_array_rest_markiert[$index] = durchgestrichen("$rest_zahl"$sudoku_array_rest_markiert[$index]);
                        }
                        echo 
"<H4>Neue Reste ($neuereste)</H4>\n";
                        
zwischen_ausgabe($sudoku_array_color$sudoku_array_rest_markiert);
                        
// if ($neuereste > $ausduenn_maximum) $ausduenn_maximum = $neuereste;
                        // $neuereste++;
                        // $ausduenn_schritte++;
                        
$sudoku_array_color[$index] = "&gt;<FONT COLOR=$farbe_braun>$zahl</FONT>&lt;";
                        echo 
"<BR>D2 - Einzige M&ouml;glichkeit in Zeile $r_1 und Spalte $c_1: Zahl $zahl\n";
                        
$neuereste 1;
                        
$punkte $punkte $punkte_art[4];
                        
$d_anzahl++;
                    }
          
                    
$anzahl++;
                    if (
$anzahl == 81) break 3;
                    
zwischen_ausgabe($sudoku_array_color, array());
                    
// Markierung weg werfen
                    
$sudoku_array_color[$last_index] = substr($sudoku_array_color[$last_index], 4, -4);
                    continue 
3;  // Nur ein Mal
                
}
            }   
// Stufe 3
      
            // Falls schon mal ausgeduennt wurde, sofort nach weiteren Moeglichkeiten schauen
            
if ($ausduennen == true) {
                
$test teste_reste($sudoku_array$sudoku_array_color$sudoku_array_rest$last_index);
                if (
$test == 1) {
                    
zwischen_ausgabe($sudoku_array_color, array());
                    
// Markierung weg werfen
                    
$sudoku_array_color[$last_index] = substr($sudoku_array_color[$last_index], 4, -4);
                    if (
$anzahl == 81) break 2;
                    continue 
2;
                }
                else continue 
1;
            }
      
            
// Einstellige, damit eindeutige Loesungen, auch mit indirekten Positionen wie Typ B
            // Waere Loesung C2 - Aufwand lohnt aber nicht
      
        
}   // Stufe 2
        //################################################################################
  
        
echo "<P>Keine (weiteren) Standard-Regeln (A, B, C) anwendbar\n";
    
        
// Erstes mal Ausduennen
        
if ($ausduennen == false) {
            
$ausduennen true;
            
$simple $a_anzahl $b_anzahl $c_anzahl;
            
// Berechnung der Ausduenn-Felder ueber bisher gefundene Felder
            
$ausduenn_felder 81 $anzahl;
            echo 
"<BR>Anzahl Ausd&uuml;nnfelder: $ausduenn_felder\n";
            
$punkte $punkte $ausduenn_felder;
        }
            
        echo 
"<H4>Reste vor dem Ausd&uuml;nnen</H4>\n";
        
zwischen_ausgabe($sudoku_array_color$sudoku_array_rest);
    
        
// Test, ob evtl. Reste leer sind, d.h. keine Zahlen moeglich sind
        
for ($index 0$index 81$index++) {   // Stufe 2
            
if ($sudoku_array_rest[$index] == "" && $sudoku_array[$index] == 0) {
                
$r_1 row_number($index) + 1;
                
$c_1 col_number($index) + 1;
                echo 
"<H2>Keine L&ouml;sung! Keine Zahl m&ouml;glich in Zeile $r_1/Spalte $c_1!</H2>\n";
                
$error 1;
                break 
2;
            }
        }   
// Stufe 2
    
        // Ausduennen nach den 5 Methoden: Box-Test, Zeilen-/Spalten-Test, N-Tupel, X-Wing, Goldene Kette