|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 173
|
Verfasst am: 08.01.2025, 23:44 Titel: |
|
|
Hallo grindstone,
wenn du deine Single-Suche permanent durchlaufen läßt, musst du im schlimmsten Fall also alle 81 Zellen abklappern, um nach Singles zu suchen.
Würde es nicht reichen, ab der zuletzt eingetragenen Stelle nach Singles zu suchen? Danach geht es doch eh wieder in der Zelle (1,1) los.
Was sich dann als Single herausstellt, wird eben dann als solcher erkannt, nur halt einen Durchlauf später. Ist das nicht effektiver, als bei jedem Eintrag sofort alle 81 Zellen nach möglichen, sich jetzt ergebenen Singles "abzuklappern"?
Oder sehe ich das falsch?
Gruß Revilo |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 387
|
Verfasst am: 09.01.2025, 00:16 Titel: |
|
|
Die 6 ist zu Beginn nicht ausgeschlossen in der Ecke (1,1), das hast du richtig erkannt. Später durch das finden diverser Singles wird sie aber schließlich doch ausgeschlossen. _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1272 Wohnort: Ruhrpott
|
Verfasst am: 09.01.2025, 00:58 Titel: |
|
|
Wenn beim Ausschließen von Zahlen (zeilen- spalten- und quadratweise) in einem Feld nur noch eine mögliche Zahl übrigbleibt, wird sie automatisch gesetzt, so, als ob ich sie eingegeben hätte. Und dann wird erneut überprüft, ob dadurch weitere Zahlen ausgeschlossen werden können. Das gibt in den meisten Fällen eine Kettenreaktion.
Manchmal bekomme ich damit sogar schon eine Lösung, bevor ich alle Zahlen eingegeben habe.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 387
|
Verfasst am: 12.01.2025, 14:05 Titel: |
|
|
Erneute QBasic Enüchterung:
Habe einen Backtracking Algorithmus von https://www.geeksforgeeks.org/sudoku-backtracking-7/ übersetzt. Und erhalte beim Ausführen die Fehlermeldung: Zitat: | Außerhalb des Stapelbereichs |
(Die rekursive Funktion hat sich zu oft selbst aufgerufen, QBasic erlaubt nur eine sehr begrenzte Anzahl von rekursiven Aufrufen...)
https://github.com/SpionAtom/QBasic/blob/main/SUDOSOLV.BAS
Man kann dieses Programm zum Glück mit QB64 ausführen, da gibt es diese knappen Einschränkungen nicht und alles funktioniert wunderbar.
Ich muss mich also nun aufmachen, das ganze in eine nicht-rekursive Form zu pressen. _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 173
|
Verfasst am: 12.01.2025, 20:35 Titel: |
|
|
Hallo SpionAtom,
Zitat: | Außerhalb des Stapelbereichs |
Genau dieselbe Fehlermeldung habe ich auch schon mehrfach erhalten.
Man kann von einem "Herzkranken" nun mal nicht erwarten, dass er einen "Marathon-Lauf" durchhält.
Also muss man die ganze Sache so "umstricken", dass der "Herzpatient" am Ziel ankommt, ohne ihn zu überfordern.
Die Frage ist also, wie?
Gruß Revilo |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 387
|
Verfasst am: 13.01.2025, 00:24 Titel: |
|
|
Das erste Video erklärt den Algorithmus ziemlich gut, ist allerdings englisch:
https://www.youtube.com/watch?v=cbUd4VVyKto
Das zweite Video gibt sogar den Pseudocode vor, also die Bauanleitung ohne eine konkrete Programmiersprache zu verwenden:
https://www.youtube.com/watch?v=J0N1G33wNlQ
Das sieht ziemlich easy aus. _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 387
|
Verfasst am: 13.01.2025, 08:50 Titel: |
|
|
Es war einigermaßen leicht zu implementieren (ich habe ja auch die Erfahrung ).
Ein iterativer Solver, der mit Live-Anzeige des Lösens ca. 3-10 Sekunden braucht.
Der Algorithmus ist tatsächlich sehr schön zu verstehen und man muss nicht mit Rekursionsparametern und Rückgabewerten hantieren.
https://github.com/SpionAtom/QBasic/blob/main/SUDOSOL2.BAS
Einzig bin ich mir nicht sicher, ob bei einem ungültigen Sudoku das ganze nicht in eine Endlosschleife läuft, der Test hat zumindest gut funktioniert.
EDIT: Für ein etwas schwierigeres Sudoku brauchte der Solver von 15:15 - 18:23 Uhr, in der Dosbox, unkompiliert, mit Zwischendurchausgabe. Dennoch sind über drei Stunden etwas zu viel des Guten.
Als nächstes muss ich also an der Mischung zwischen Lösungsstrategien und Backtracking arbeiten, sodass die Gesamtzeit kleiner wird.
(QB64 braucht 7 Sekunden!) _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 173
|
Verfasst am: 14.01.2025, 23:02 Titel: |
|
|
Hallo SpionAtom,
wir kommen der Sache näher.
Deine empfohlenen Videos waren mir leider zu "englisch-belastet" also entsprechend wenig verständlich. Dennoch danke ich dafür.
Dein Code war wesentlich einleuchtender, weil in QBasic geschrieben, was ich verstehe.
Ich hätte noch eine Nachfrage zu deinem Code:
Code-Zeile 33 - 42 liefert praktisch das Original-Sudoku, was zu lösen ist.
Code-Zeile 55 - 64 liefert genau dieses Sudoku, falls es nicht lösbar ist.
Welchen Zweck haben die Code-Zeilen 44 - 53 ?
Zitat: | Einzig bin ich mir nicht sicher, ob bei einem ungültigen Sudoku das ganze nicht in eine Endlosschleife läuf |
Wann wäre es denn eine Endlosschleife? .... Richtig, wenn es keinen Lösungsfortschritt mehr gibt.
Lässt man das gesamte Programm also z.B. 3 x durchlaufen, ohne einen Lösungsfortschritt zu erhalten, ist doch anzunehmen, dass auch weitere
Durchläufe ebenso fortschrittlos sein werden.
3 fortschrittlose Durchläufe sollten einem also sagen, dass es mit den bisherigen Mitteln nicht mehr weitergeht.
Man steht also vor der Entscheidung, entweder ein zusätzliches, neue Mittel
(Lösungstechniken derer es über 40 gibt) zu implementieren, oder ab jetzt zu probieren, also mit Backtracking als ultimativ letzte Strategie weiterzumachen.
Wenn es wiederum 3 ergebnislose Durchläufe (diesmal einschließlich Backtracking) gibt, kann man wohl annehmen, dass es gar keine Lösung für das jeweilige Sudoku gibt. Eine Endlosschleife kann man also vermeiden, wenn man eine Art "Erfolglos"-Zähler einführt, der bis max. 3 durchläuft.
Nur mal so eine Idee. Ich mache es jedenfalls so und es funktioniert.
Zitat: | Als nächstes muss ich also an der Mischung zwischen Lösungsstrategien und Backtracking arbeiten, sodass die Gesamtzeit kleiner wird. | Richtig!
Ich löse von Hand jeden Tag mindestens ein Sudoku aus der Zeitung.
Da begegnen mir öfter auch mal echt schwere Sudokus.
Dennoch musste ich selten, fast nie, auf spezielle Lösungstechniken wie
etwa "X-Wing" zugreifen.
Bisher reichte es aus, nur zu schauen, wo nur noch ein Wert eintragbar ist.
Eben das klassische, optische "SCANNEN".
Jeder erfolgreich gefundene Eintrag macht diesen eingetragenen Wert in seiner Umgebung unmöglich (Sudoku-Regeln).
Wenn diese "Solo-Suche" 3 mal fortschrittlos durchlief, suche ich nach echten Zwillingen, also nach Zellen (i, j ) in denen nur noch 2 Werte(w1 und w2) möglich sind. Wenn ich auf eine derartige Zelle treffe, suche ich nach einer Zelle (x, y), in der w1 und w2 ebenfalls nur noch als gemeinsames, alleiniges "Pärchen" vorkommen können.
Die Suche erfolgt zeilen-, spalten- und blockweise.
Wenn ich eine solche Zelle(x, y) gefunden habe, weiß ich zwar noch nicht, wo w1 und wo w2 einzutragen ist, aber ich weiß, dass es in der jeweiligen Zeile i, der jeweiligen Spalte j und dem jeweiligen Block (i, j) kein w1 bzw. w2 mehr geben darf( Sudoku-Regeln). Ich eliminiere also entsprechend.
Wenn sich nach 3 maligem Durchlauf (diesmal einschließlich Zwillingssuche)
kein Lösungsfortschritt mehr ergibt, gehe ich zur ultimative Waffe/Strategie
(Backtracking).
Wenn das ganze Programm, (jetzt einschließlich Backtracking) nach 3 Durchläufen keinen Lösungsfortschritt liefert, gibt es wohl überhaupt keine
Lösung für dieses betreffende Sudoku.
Bis zur "Zwillingssuche" bin ich bereits gekommen. Aber das Backtracking, als ultimativer "Waffe" bereitete mir bisher Probleme.
Dein Code hat diese erheblich verringert. Vielen Dank dafür.
Rechne bitte aber trotzdem immer noch damit, dass sich meinerseits einige
Nachfragen ergeben könnten. (Backtracking ist für mich immer noch eine völlig neue, erstmalig angewendete Denkweise, mit der ich mich erst mal "anfreunden " muss). Aber es werden bestimmt weniger Nachfragen sein, als es bisher waren. Dank deiner Hilfe habe ich inzwischen viel hinzulernen dürfen. Danke dafür.
Gruß Revilo |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 387
|
Verfasst am: 15.01.2025, 00:07 Titel: |
|
|
Die drei Data-Blöcke sind enfach verschiedene Sudokus, die ich in meinem Programm laden kann. In Zeile 9 gebe ich an, welchen Data-Block ich lade.
Du kannst dort beliebig viele weitere Sudokus eintragen. Also 9 Datazeilen, die dein Sudo repräsentieren. Vorangestellt muss nur eine Zeilenbezeichnung sein wie S1: oder S2:
Und in Zeile 9 wählst du mit RESTORE Zeilenbezeichnung ein beliebiges vorhandenes Sudoku aus.
Mein Backtracking-Algorithmus funktioniert doch ganz gut. Wenn es eine valide Lösung gibt, dann wird sie auch gefunden. Wenn es keine valide Lösung gibt, dann bekomme ich das auch mit. Nur im schlimmsten Fall sucht er leider noch stundenlang. _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 173
|
Verfasst am: 15.01.2025, 01:09 Titel: |
|
|
Hallo SpionAtom,
wenn du möchtest, dass ich dich verstehe, verzichte bitte auf "fach-chinesisch".
Was bedeutet "valide Lösung"?
Wie findest du meine Vorgehensweise bei der Single- bzw. Zwillingssuche?
Was hältst du von meiner Anregung zum 3 - maligen Durchlauf?
Gruß Revilo |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 387
|
Verfasst am: 15.01.2025, 08:29 Titel: |
|
|
Valide Lösung = Gültige Lösung = Einfach ein korrekt gelöstes Sudoku.
(Hingegen eine invalide Lösung wäre ein falsch gelöstes Sudoku - also fehlerhaft, oder ein Sudoku ohne Lösung, oder ein Sudoku mit mehreren Lösungen)
Dreimaliger Durchlauf ist eigentlich unnötig.
Man hat seine Liste von Strategien: Full House, Singles, Hidden Singles, X-Wing....
Man klappert diese Liste ab, bis man was gefunden hat. Und dann klappert man diese Liste erneut ab, bis man was gefunden hat, usw.
Wurde die komplette Liste abgeklappert, ohne dass man was gefunden hat, dann bringt es auch keine neuen Ergebnisse, wenn man das ganze noch zwei- dreimal laufen lässt. _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 173
|
Verfasst am: 16.01.2025, 15:38 Titel: |
|
|
Hallo SpionAtom,
im Grunde hast du natürlich recht.
Das ist eben ein Zeichen meiner fachlichen Unsicherheit.
Wenn die gesamte Liste der Strategien einmal erfolglos durchgelaufen ist,
wird das erneute Abklappern der Liste genauso erfolglos sein.
Ich lasse das ganze zwei- oder dreimal durchlaufen, nur um praktisch Gewissheit über eine bereits bestehende Gewissheit zu bekommen.
(Doppelt genäht hält besser ). Hinsichtlich der Bearbeitungszeit macht das keinen großen Unterschied.
Aber wenn sich doch ein Fehler eingeschlichen hat, kann dessen Suche Wochen dauern. Da sich dieser Fehler oft sehr gut versteckt, (manchmal ist es nur ein Komma, wo eigentlich ein Semikolon hingehört) stellt man praktisch alles, selbst das sauber funktionierende, unter "Generalverdacht".
Statt den einen Fehler zu finden, baut man eventuell einen zusätzlichen ein.
Genau deshalb ist mein Programm gespickt, mit "Zwischen-Infos":
print: "Bis hier ok.":sleep
Wenn man nicht genau weiß, was man tut, sollte man zumindest wissen, bis wohin man etwas richtig gemacht hat. Wenn es einen Fehler gibt, kann er nur danach aufgetreten sein. Das grenzt die Suche schon mal etwas ein.
Gruß Revilo |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 387
|
Verfasst am: 17.01.2025, 12:32 Titel: |
|
|
Ja, die Fehlersuche (oder Debugging im Allgemeinen) mache ich in QBasic genau so mit den Zwischen-PRINTs, geht ja nicht anders.
Ich habe meinen Solver nun soweit, dass erst einige Lösungsstrategien probiert werden, ehe per Backtracking das ganze gelöst wird:
https://github.com/SpionAtom/QBasic/blob/main/SUDOSOLV.BAS
Im Repo liegt ebenfalls ein Testsudoku, welches ca. 40 Sekunden Lösungszeit braucht.
https://github.com/SpionAtom/QBasic/blob/main/m1.sud
Nun kann ich nach Lust und Laune weitere Strategien einbauen (Zwillingspaare zb, oder x-wing,...), jedoch ist das Lösungsprogramm erstmal funktionsfähig und somit fertig! _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 173
|
Verfasst am: 18.01.2025, 12:12 Titel: |
|
|
Hallo SpionAtom.
Glückwunsch. Wenn ich bedenke, wie lange ich daran schon umherbastele.
Du machst das in wenigen Tagen, während ich Monate brauche.
Kompliment.
Das ist aber nun mal der Unterschied zwischen einem Profi und einem Laien.
Jetzt weiß ich zumindest schon mal, wie "der Hase überhaupt laufen muss".
Wofür steht eigentlich die 1. Zeile: DEFINT A-Z?
Vermutung: Alle Variablen, die mit einem Buchstaben beginnen, werden als integer definiert. So erspart man sich die Formatbezeichner. Richtig?
Was ist eine "initiale Ziffer"?
Nur, um mich nochmal zu vergewissern: CHR$(27) steht für ESCAPE, richtig?
Gruß und schönes WE Revilo |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 387
|
Verfasst am: 18.01.2025, 12:58 Titel: |
|
|
Danke, danke! Macht ja auch Spaß etwas zu knobeln und an Programmen zu basteln.
Revilo hat Folgendes geschrieben: |
Wofür steht eigentlich die 1. Zeile: DEFINT A-Z?
Vermutung: Alle Variablen, die mit einem Buchstaben beginnen, werden als integer definiert. So erspart man sich die Formatbezeichner. Richtig?
|
Richtig. Du kannst für alle Befehle auch in der Hilfe nachschauen.
Revilo hat Folgendes geschrieben: |
Was ist eine "initiale Ziffer"?
|
Initial heißt so viel wie "zu Beginn". In meinem Programm also die Ziffern, die zu Beginn für das Sudoku vorgegeben sind. Diese kopiere ich für den Backtracking-Algorithmus extra in ein eigenes Array.
Code: | 'Kopiere zun„chst das sudo-Array in sudoFix. Wenn in sudoFix ein Wert
'ungleich 0 steht, so darf dieser w„hrend des L”sens nicht mehr ge„ndert
'werden.
DIM sudoFix(0 TO 8, 0 TO 8)
FOR zeile = 0 TO 8
FOR spalte = 0 TO 8
sudoFix(zeile, spalte) = sudo(zeile, spalte)
NEXT
NEXT |
Denn diese Werte müssen ja nicht durchprobiert werden, die sind fix.
Revilo hat Folgendes geschrieben: |
Nur, um mich nochmal zu vergewissern: CHR$(27) steht für ESCAPE, richtig? |
Das ist korrekt, auch das kann man in der QBasic Hilfe nachgucken bei Ascii Codes. _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 173
|
Verfasst am: 18.01.2025, 23:38 Titel: |
|
|
Hallo SpionAtom.
sicherlich kann man alles irgendwo nachlesen.
Sorry, aber zwischen lesen und tatsächlich verstehen können dennoch Welten liegen.
Meine Vermutung bezüglich DEFINT A-Z war offenbar richtig.
Aber was mache ich, wenn ich z.B. eine Variable Namens "Sudokuwort" habe?
Nach dieser Definition würde sie als "Integer" definiert werden.
Ich brauche sie aber nicht als integer sondern als String mit einer Länge von 81 Zeichen. Wie muss ich diese "Ausnahme" definieren?
Aber so ist nun mal das Leben.
Ein Laie muss sich quälen, ein Profi kann darüber lächeln, weil er weiß, wie es geht. Aber dennoch hat jeder Profi mal als Laie angefangen.
Gruß Revilo |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1272 Wohnort: Ruhrpott
|
Verfasst am: 19.01.2025, 00:05 Titel: |
|
|
Revilo hat Folgendes geschrieben: | Aber was mache ich, wenn ich z.B. eine Variable Namens "Sudokuwort" habe?
Nach dieser Definition würde sie als "Integer" definiert werden. |
Steht in der QB-Hilfe:
"Ein Datentyp-Suffix (%, &, !, #, or $) hat immer Vorrang vor einer DEFtype-Anweisung."
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 387
|
Verfasst am: 19.01.2025, 18:34 Titel: |
|
|
Das mit der QBasic Hilfe ist kein Hinweis zum Ärgern. Es ist überall hilfreich, wenn man sich mit so Hilfen auseinandersetzt.
Außerdem bekommst du damit direkt Hilfe und musst nicht auf deine Forumskollegen auf Antwort warten. Wenn nach dem Lesen der Hilfe dann immer noch Fragen bestehen, frag hier gerne nach.
Aber sonst. Wenn du DEFINT nicht kennst, gehe zu dieser Stelle in deinem Programm und drücke F1, schneller geht's eigentlich nicht _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4686 Wohnort: ~/
|
Verfasst am: 20.01.2025, 20:34 Titel: |
|
|
Da ich vor QBasic mit einem anderen BASIC-Dialekt zu tun hatte, der zwar ein paar Jahre älter, aber bereits deutlich moderner umgesetzt war, war QBasic für mich eigentlich ein Rückschritt. Die integrierte Hilfe war eine der wenigen echten Glanzlichter. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 173
|
Verfasst am: 20.01.2025, 22:12 Titel: |
|
|
Hallo SpionAtom, hallo grindstone,
nach dem, was ich bisher hier lesen durfte gibt es offenbar drei Möglichkeiten (respektive Befehle) eine Variable a als integer zu definieren.
'1) DEFINT A-Z
'2) DIM a%
'3) DIM a as INTEGER.
Wenn es drei Möglichkeiten gibt, wird jede wohl auch ihren eigenen speziellen Sinn und Zweck haben. Sonst bräuchte man ja nur eine dieser drei.
Frage:
Was ist der Unterschied zwischen diesen drei Möglichkeiten, eine Variable a als Integer zu definieren?
Gruß Revilo |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|