das Sudokuproblem

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
der kleine Fritz
User
Beiträge: 25
Registriert: Montag 18. Dezember 2023, 11:33

Hallo liebe Pythonprofis,

als gealteter Maschinenbauer bringe ich mir seid einiger Zeit autodidaktisch Python bei.
Dazu ackere ich das sehr interessante Pythonaufgabenbuch "Python Challenge" durch.

Da gibt es eine Aufgabe bei der ich einfach nicht weiterkomme.
Es geht darum über ein Array nachzuweisen das ein vorgegebenes Sudoku sowohl der Zeilen, Päckchen und Reihen immer die Zahlen 1-9 enthält.

Ich habe es nun geschafft die Zeilen des Arrays zu prüfen, was auch funktioniert. Aber bei der Überprüfung der "3x3 Päckchen" funktioniert es nicht mehr.
Hat jemand einen Tipp?
Danke und Grüße.

Code: Alles auswählen

import numpy as np
#Erzeugung Array mit Sudokuzahlen und Umwandlung in mehrdimensionales Array
sudokuarray = np.array ([1,2,3,4,5,6,7,8,9,4,5,6,7,8,9,1,2,3,7,8,9,1,2,3,4,5,6,2,1,4,3,6,5,8,9,7,3,6,5,8,9,7,2,1,4,8,9,7,2,1,4,3,6,5,5,3,1,6,4,2,9,7,8,6,4,2,9,7,8,5,3,1,9,7,8,5,3,1,6,4,2])
sudokuarray = sudokuarray.reshape (9,9)
ergebnislistezeilen = []
ergebnispäckchen = []

#Funktion zur Prüfung ob Zahlen von 1-9 in dem Prüfbereich des Sudoku enthalten sind
def prüf (bereich):
    zahlen = list(range(1,10))
    if set(zahlen).issubset(bereich):
        ergebnis = "TRUE"
    else:
        ergebnis = "FALSE"
    return ergebnis

#Schleife die alle 9 Zeilen prüft mit der gegebenen Funktion, ob diese alle Zahlen von 1-9 enthalten
a = 0
while a < 9:
    z1 = sudokuarray [a,:9]
    bereich = z1
    prüf (bereich)
    ergebnis = prüf(bereich)
    ergebnislistezeilen.append (ergebnis)
    a = a+1

#Schleife die alle "Päckchen" prüft ob diese alle Zahlen von 1-9 enthalten
p1 = sudokuarray [0:3, 0:3]

bereich = p1
prüf (bereich)
ergebnis = prüf(bereich)
ergebnispäckchen.append (ergebnis)

print ("Zeilenabfrage:",ergebnislistezeilen)
print ("Päckchenabfrage:",ergebnispäckchen)
print (sudokuarray)
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mal ein paar Anmerkungen zum Code, bevor wir auf das Problem eingehen:

In der Funktion pruef verwendest du Strings als Wahrheitswerte. Das macht man nich. Es gibt True & False, und die sollte man auch benutzen. Wenn man das tut, kann man sich auch noch gleich das unnoetige if/else sparen. Zu guter letzt ist die Teilmengenbeziehung hier zwar mathematisch korrekt, aber kann von der staerkeren Gleichheit ersetzt werden, und das erhoeht die Klarheit. Die wird dann also

Code: Alles auswählen

def pruef(bereich):
     return set(range(1, 10)) == set(bereich)
Die while-Schleife ist auch quatsch, wer einen Index von Hand anlegt, prueft, und inkrementiert, will eine for-Schleife:

Code: Alles auswählen

for a in range(10):
  ....
Jetzt zu deinem Problem: es gibt 9 Paeckchen, und fuer jedes Packchen musst du erstmal die Position seiner oberen linken Ecke bestimmen. Also 0, 0 fuer ganz oben links, dann (0, 3) fuer das mittlere, dann (0, 6) fuer das rechte obere, dann (3, 0) fuer das linke mittlere, etc. Fuer jede Start-Koordinate gibt es dann 9 Positionen der einzelnen Felder, und die sind einfach nur jeweils die relativen Koordinaten mit Offsets 0 - 2 in beiden Dimensionen, einfach zu bestimmen mit zwei geschachtelten for-Schleifen.

Code: Alles auswählen

def paeckchen_beginn(index):
     assert index in range(9) # Zur Sicherheit
     return index // 3 * 3, index % 3 * 3


def paeckchen_koordinaten(index):
    i, j = paeckchen_beginn(index)
    res = []
    for y in range(3):
        for x in range(3):
            res.append((i + y, j + x))

    return res


for p in range(9):
     print(paeckchen_koordinaten(p))
der kleine Fritz
User
Beiträge: 25
Registriert: Montag 18. Dezember 2023, 11:33

Vielen Dank! Ich bin leider mit meinem Wissen noch nicht in die Tiefen von Python vorgestoßen um das in Form vorher so umzusetzen, daher fragte ich ja.
Das mit dem String (False / True) ist absolut richtig. Bei dem Rest muss ich mich noch einlesen um es bis ins Detail zu verstehen. Aber ich weiß ungefähr was gemeint ist.
Ganz lieben Dank, bis hierhin!
Benutzeravatar
ThomasL
User
Beiträge: 1367
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Hi kleiner Fritz,

da du schon mit Numpy arbeitest, hier mal ein Code Snippet wie ich das mal vor Jahren "gelöst" habe.
Aus eigener Erfahrung kann ich sagen, das ich viel durch anderer Leute Code gelernt habe.

Viel Spaß bei deiner Reise in die Python Welt.

Code: Alles auswählen

import numpy as np

matrix = [[8, 2, 7, 1, 5, 4, 3, 9, 6],
          [9, 6, 5, 3, 2, 7, 1, 4, 8],
          [3, 4, 1, 6, 8, 9, 7, 5, 2],
          [5, 9, 3, 4, 6, 8, 2, 7, 1],
          [4, 7, 2, 5, 1, 3, 6, 8, 9],
          [6, 1, 8, 9, 7, 2, 4, 3, 5],
          [7, 8, 6, 2, 3, 5, 9, 1, 4],
          [1, 5, 4, 7, 9, 6, 8, 2, 3],
          [2, 3, 9, 8, 4, 1, 5, 6, 7]]

board = np.asarray(matrix, dtype=np.int)

quadrants = []
for row in range(3):
    for col in range(3):
        quadrants.append(board[row*3:(row+1)*3, col*3:(col+1)*3])

rows = []
columns = []
for i in range(9):
    rows.append(board[i,:])
    columns.append(board[:,i])

def pruefe(elemente, location):
    for pos, element in enumerate(elemente):
        if len(set(element.flatten().tolist())) != 9:
            print(f'Error in {location} {pos}')

pruefe(quadrants, 'Quadrant')
pruefe(rows, 'Reihe')
pruefe(columns, 'Spalte')

board[8,5] = 5

pruefe(quadrants, 'Quadrant')
pruefe(rows, 'Reihe')
pruefe(columns, 'Spalte')

#--Ausgabe--
# Error in Quadrant 7
# Error in Reihe 8
# Error in Spalte 5
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Statt Kommentare vor Funktionen zu schreiben, schreibt man Doc-Strings, denn die kann man automatisch auch für Hilfetexte auslesen.
Wenn man schon kein sauberes Hauptprogramm hat, so sollte man doch nicht Variableninitialisierung und Funktionen mischen.
ergebnispäckchen wird zudem über 20 Zeilen vor der Benutzung definiert; Variablen sollten erst eingeführt werden, wenn sie auch gebraucht werden.
`sudokuarray` ist bereits ein 9x9-Array. Deshalb kann man einfach über Zeilen und Spalten iterieren, ohne while und ohne Index.
In Variablennamen sollten keine Datentypen vorkommen. Also `sudoku_feld` statt array.
Man muß nicht alles an Variablen binden, vor allem `bereich = z1` ist total überflüssig.

Das könnte so aussehen:

Code: Alles auswählen

import numpy as np

def pruef(bereich):
    """ Funktion zur Prüfung ob Zahlen von 1-9 in dem Prüfbereich des Sudoku enthalten sind. """
    return set(range(1,10)) == set(bereich.ravel())

#Erzeugung Array mit Sudokuzahlen und Umwandlung in mehrdimensionales Array
sudoku_feld = np.array([1,2,3,4,5,6,7,8,9,4,5,6,7,8,9,1,2,3,7,8,9,1,2,3,4,5,6,2,1,4,3,6,5,8,9,7,3,6,5,8,9,7,2,1,4,8,9,7,2,1,4,3,6,5,5,3,1,6,4,2,9,7,8,6,4,2,9,7,8,5,3,1,9,7,8,5,3,1,6,4,2])
sudoku_feld = sudoku_feld.reshape(9,9)

ergebnis_zeilen = []
for zeile in sudoku_feld:
    ergebnis_zeilen.append(pruef(zeile))

ergebnis_spalten = []
for spalten in sudoku_feld.T:
    ergebnis_spalten.append(pruef(spalten))
Oder kurz:

Code: Alles auswählen

import numpy as np
ergebnis_zeilen = [
    pruef(zeile)
    for zeile in sudoku_feld
]

ergebnis_spalten = [
    pruef(spalten)
    for spalten in sudoku_feld.T
]
der kleine Fritz
User
Beiträge: 25
Registriert: Montag 18. Dezember 2023, 11:33

ThomasL hat geschrieben: Freitag 9. Februar 2024, 11:21 Hi kleiner Fritz,

da du schon mit Numpy arbeitest, hier mal ein Code Snippet wie ich das mal vor Jahren "gelöst" habe.
Aus eigener Erfahrung kann ich sagen, das ich viel durch anderer Leute Code gelernt habe.

Viel Spaß bei deiner Reise in die Python Welt.

Code: Alles auswählen

import numpy as np

matrix = [[8, 2, 7, 1, 5, 4, 3, 9, 6],
          [9, 6, 5, 3, 2, 7, 1, 4, 8],
          [3, 4, 1, 6, 8, 9, 7, 5, 2],
          [5, 9, 3, 4, 6, 8, 2, 7, 1],
          [4, 7, 2, 5, 1, 3, 6, 8, 9],
          [6, 1, 8, 9, 7, 2, 4, 3, 5],
          [7, 8, 6, 2, 3, 5, 9, 1, 4],
          [1, 5, 4, 7, 9, 6, 8, 2, 3],
          [2, 3, 9, 8, 4, 1, 5, 6, 7]]

board = np.asarray(matrix, dtype=np.int)

quadrants = []
for row in range(3):
    for col in range(3):
        quadrants.append(board[row*3:(row+1)*3, col*3:(col+1)*3])

rows = []
columns = []
for i in range(9):
    rows.append(board[i,:])
    columns.append(board[:,i])

def pruefe(elemente, location):
    for pos, element in enumerate(elemente):
        if len(set(element.flatten().tolist())) != 9:
            print(f'Error in {location} {pos}')

pruefe(quadrants, 'Quadrant')
pruefe(rows, 'Reihe')
pruefe(columns, 'Spalte')

board[8,5] = 5

pruefe(quadrants, 'Quadrant')
pruefe(rows, 'Reihe')
pruefe(columns, 'Spalte')

#--Ausgabe--
# Error in Quadrant 7
# Error in Reihe 8
# Error in Spalte 5
Vielen Dank!
der kleine Fritz
User
Beiträge: 25
Registriert: Montag 18. Dezember 2023, 11:33

Also ich habe mir jetzt ein paar Tips der Forummitglieder zu Herzen genommen und mal einen Code geschrieben, der die Zeilen und Spalten eines vorgegebenen Soduku auf Richtigkeit prüft.
Aber warum schafft es Python nicht bei einem 2-dimensionalen Numpy-Array auch ein "Päckchen" zu überprüfen?
Vielleicht kann das einer von euch einem Laien wie mir erklären... Danke!

Code: Alles auswählen

import numpy as np
#Erzeugung Array mit Sudokuzahlen und Umwandlung in mehrdimensionales Array
sudokuarray = np.array ([1,2,3,4,5,6,7,8,9,4,5,6,7,8,9,1,2,3,7,8,9,1,2,3,4,5,6,2,1,4,3,6,5,8,9,7,3,6,5,8,9,7,2,1,4,8,9,7,2,1,4,3,6,5,5,3,1,6,4,2,9,7,8,6,4,2,9,7,8,5,3,1,9,7,8,5,3,1,6,4,2])
sudokuarray = sudokuarray.reshape (9,9)
ergebnislistezeilen = []
ergebnislistespalten = []
ergebnislistepäckchen = []

#Funktion zur Prüfung ob Zahlen von 1-9 in dem Prüfbereich des Sudoku enthalten sind
def prüf (bereich):
    return set(range(1, 10)) == set(bereich)

#Schleife die alle 9 Zeilen prüft mit der gegebenen Funktion, ob diese alle Zahlen von 1-9 enthalten
for a in range (9):
    bereich = sudokuarray [a,:]
    prüf (bereich)
    ergebnis = prüf(bereich)
    ergebnislistezeilen.append (ergebnis)

#Schleife die alle 9 Spalten prüft mit der gegebenen Funktion, ob diese alle Zahlen von 1-9 enthalten
for b in range (9):
    bereich = sudokuarray [:,b]
    prüf (bereich)
    ergebnis = prüf(bereich)
    ergebnislistespalten.append (ergebnis)
    
         

#Prüfung der einzelnen Array-Päckchen

bereich = sudokuarray [0:3,0:3]
prüf (bereich)
ergebnis = prüf(bereich)
ergebnislistepäckchen.append (ergebnis)
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@der kleine Fritz: warum denkst Du, dass es das sollte?
Warum rufst Du `prüf` auf, ohne was mit dem Ergebnis zu tun?
Meinen Beitrag und die Anmerkung zu den Indizes hast du ja geflissentlich ignoriert.

Die Kästchenprüfung sieht dann noch so aus:

Code: Alles auswählen

ergebnis_kaestchen = [
    pruef(kaestchen)
    for kaestchen in np.swapaxes(sudoku_feld.reshape(3,3,3,3), 1, 2).reshape(9,9)
]
der kleine Fritz
User
Beiträge: 25
Registriert: Montag 18. Dezember 2023, 11:33

@Sirius3
Der Code geht natürlich danach nach noch weiter in dem mir das Ergebnis „True / False“ ausgedruckt werden sollte.
Ich habe deinen Hinweis vorher nicht ignoriert sondern nicht verstanden und ich will gerne meinen Code wirklich verstehen und nicht nur Lösungen reinkopieren, dabei lerne ich ja nichts.
Aber zurück zu meiner Frage, was ist den Grund das Python bei 2-dimensionalen Numpy Arrays zwar die Zeilen und Spalten so leicht prüft aber bei den Päckchen es nicht so leicht klappt. Immerhin hat Python doch von mir die notwendigen Indexe benannt bekommen wo es nur noch prüfen muss ob die Zahlen 1-9 enthalten sind.
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@der kleine Fritz: Wie jede andere Programmiersprache auch, macht Python das was der Programmierer sagt, und nicht das was er meint. Wenn Python etwas „nicht kann“, dann ist das Problem das Du nicht das ausgedrückt hast was Du willst, sondern bestenfalls etwas ähnliches.

Wenn der Code nicht macht was Du willst, musst Du schauen wie die Zwischenergebnisse aussehen und an welcher Stelle das dann nicht mehr so aussieht wie Du erwartest das es aussehen sollte. Dann weisst Du wo Du einen Fehler gemacht hast.

Du hast da einen Kommentar stehen „#Prüfung der einzelnen Array-Päckchen“ und dann Code der das hier macht:

Code: Alles auswählen

In [100]: def prüf (bereich):
     ...:     return set(range(1, 10)) == set(bereich)
     ...: 

In [101]: sudokuarray
Out[101]: 
array([[1, 2, 3, 4, 5, 6, 7, 8, 9],
       [4, 5, 6, 7, 8, 9, 1, 2, 3],
       [7, 8, 9, 1, 2, 3, 4, 5, 6],
       [2, 1, 4, 3, 6, 5, 8, 9, 7],
       [3, 6, 5, 8, 9, 7, 2, 1, 4],
       [8, 9, 7, 2, 1, 4, 3, 6, 5],
       [5, 3, 1, 6, 4, 2, 9, 7, 8],
       [6, 4, 2, 9, 7, 8, 5, 3, 1],
       [9, 7, 8, 5, 3, 1, 6, 4, 2]])

In [102]: sudokuarray[0:3, 0:3]
Out[102]: 
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [103]: prüf(sudokuarray[0:3, 0:3])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[103], line 1
----> 1 prüf(sudokuarray[0:3, 0:3])

Cell In[100], line 2, in prüf(bereich)
      1 def prüf (bereich):
----> 2     return set(range(1, 10)) == set(bereich)

TypeError: unhashable type: 'numpy.ndarray'

In [104]: set(sudokuarray[0:3, 0:3])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[104], line 1
----> 1 set(sudokuarray[0:3, 0:3])

TypeError: unhashable type: 'numpy.ndarray'
1. Prüft der Code nur das erste Päckchen und nicht alle, und
2. löst die `prüf()`-Funktion eine Ausnahme aus.

Die beim `set()`-Aufruf passiert. Das Päckchen hat einen entscheidenden Unterschied zu einer Zeile oder einer Spalte. Schau Dir mal an was `set()` macht und wie viele Elemente so eine Zeile/Spalte enthält und wie viele Elemente ein Päckchen enthält, und was jeweils die Datentypen davon sind.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@der kleine Fritz: wenn Du etwas nicht verstehst, dann kannst Du gerne nachfragen.
der kleine Fritz
User
Beiträge: 25
Registriert: Montag 18. Dezember 2023, 11:33

@sirius3
vielen Dank für den Tipp! Ich werde mich mal versuchen da reinzudenken und im ersten Schritt nach set() googlen.
Ich melde mich wenn ich was nicht verstehe...
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Hab zu wenig Geduld umd Sudokus mit Papier und Bleistift zu lösen. Hab deswegen das hier zusammengehackt. Ich habe es mit genau einem Sudoku aus der Rentner-Bravo ausprobiert, weiß also nicht, ob es korrekt ist.

Code: Alles auswählen

from collections import Counter
from copy import deepcopy
from itertools import chain

import numpy as np


def fix(cells):
    for cell in cells:
        counter = Counter(chain(*cell))
        for num, count in counter.items():
            if count == 1:
                for each in cell:
                    if num in each:
                        each.clear()
                        each.add(num)
                        break


def main():

    _ = 0
    sudoku = [
        _, _, 5, 4, _, 9, 7, _, _,
        _, 6, _, _, 2, _, _, 9, _,
        4, _, 9, _, _, _, 5, _, 1,
        2, _, _, 1, _, 8, _, _, 7,
        _, 4, _, _, _, _, _, 1, _,
        5, _, _, 6, _, 3, _, _, 4,
        6, _, 7, _, _, _, 8, _, 3,
        _, 5, _, _, 8, _, _, 2, _,
        _, _, 2, 9, _, 4, 1, _, _,
    ]

    cells = np.array([{num} if num else set() for num in sudoku])
    blocks = np.swapaxes(cells.reshape(3, 3, 3, 3), 1, 2).reshape(9, 9)
    rows = cells.reshape(9, 9)
    cols = rows.T
    all_candidates = [cell or set(range(1, 10)) for cell in cells]

    for i, (candidates, cell) in enumerate(zip(all_candidates, cells)):
        if len(cell) != 1:
            r, c = divmod(i, 9)
            b = r // 3 * 3 + c // 3
            candidates.difference_update(*rows[r], *cols[c], *blocks[b])

    for candidates, cell in zip(all_candidates, cells):
        if len(cell) != 1:
            cell.update(candidates)

    while True:
        tmp = deepcopy(cells)
        fix(rows)
        fix(cols)
        fix(blocks)
        if np.array_equal(tmp, cells):
            break

    print(rows)


if __name__ == "__main__":
    main()
Ergebnis:

Code: Alles auswählen

[[{8} {1} {5} {4} {3} {9} {7} {6} {2}]
 [{7} {6} {3} {5} {2} {1} {4} {9} {8}]
 [{4} {2} {9} {8} {7} {6} {5} {3} {1}]
 [{2} {3} {6} {1} {4} {8} {9} {5} {7}]
 [{9} {4} {8} {7} {5} {2} {3} {1} {6}]
 [{5} {7} {1} {6} {9} {3} {2} {8} {4}]
 [{6} {9} {7} {2} {1} {5} {8} {4} {3}]
 [{1} {5} {4} {3} {8} {7} {6} {2} {9}]
 [{3} {8} {2} {9} {6} {4} {1} {7} {5}]]
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Mein vorheriger Code war inkorrekt. Vielleicht ist dieser besser:

Code: Alles auswählen

from collections import Counter
from copy import deepcopy
from itertools import chain

import numpy as np


def main():

    _ = 0
    sudoku = [
        1, _, 6, 9, _, _, _, _, _,
        _, 3, _, _, 5, _, _, 2, 8,
        _, _, _, _, _, _, 4, _, _,
        8, _, _, _, _, 5, _, _, _,
        _, _, _, _, _, _, _, _, 7,
        _, 2, _, _, 8, _, _, 1, 3,
        _, 4, _, _, _, _, 5, _, _,
        _, _, _, _, 1, _, 7, _, _,
        _, _, 3, _, _, 6, _, 4, 1,
    ]

    cells = np.array([{num} if num else set(range(1, 10)) for num in sudoku])
    blocks = np.swapaxes(cells.reshape(3, 3, 3, 3), 1, 2).reshape(9, 9)
    rows = cells.reshape(9, 9)
    cols = rows.T

    while True:
        before = deepcopy(cells)
        for i, cell in enumerate(cells):
            if len(cell) == 1:
                r, c = divmod(i, 9)
                b = r // 3 * 3 + c // 3
                for nums in chain(rows[r], cols[c], blocks[b]):
                    if len(nums) != 1:
                        nums.discard(*cell)
        for nonet in chain(rows, cols, blocks):
            counter = Counter(chain.from_iterable(nonet))
            for num, count in counter.items():
                if count == 1:
                    for cell in nonet:
                        if num in cell:
                            cell.clear()
                            cell.add(num)
        if np.array_equal(before, cells):
            break

    print(rows)


if __name__ == "__main__":
    main()
Ergebnis:

Code: Alles auswählen

[[{1} {8} {6} {9} {4} {2} {3} {7} {5}]
 [{9} {3} {4} {6} {5} {7} {1} {2} {8}]
 [{5} {7} {2} {1} {3} {8} {4} {6} {9}]
 [{8} {1} {7} {3} {6} {5} {2} {9} {4}]
 [{3} {6} {9} {4} {2} {1} {8} {5} {7}]
 [{4} {2} {5} {7} {8} {9} {6} {1} {3}]
 [{7} {4} {1} {2} {9} {3} {5} {8} {6}]
 [{6} {9} {8} {5} {1} {4} {7} {3} {2}]
 [{2} {5} {3} {8} {7} {6} {9} {4} {1}]]
In specifications, Murphy's Law supersedes Ohm's.
der kleine Fritz
User
Beiträge: 25
Registriert: Montag 18. Dezember 2023, 11:33

Das sind zwar schönes Lösungen die pillmuncher reingesetzt hat, aber ich bin längst nicht soweit um diese zu komplett zu verstehen.
Ich habe jetzt mal einen code geschrieben, die ein 9x9 Array erzeugt und anschließend Stelle für Stelle (der ersten Zeile erstmal) prüft ob die Zufallszahl bereits vorhanden ist.
Wenn nein dann soll die Zahl eingesetzt werden. Und hier kommt das Problem, auch die Zahl wird immer eingesetzt, auch wenn sie bereits vorhanden ist.
Irgendwas blockiert hier in meiner Rübe und ich finde den Fehler nicht. Ich bräuchte nur einen kleinen Schubser um es zu verstehen. Ich hab es auch mit einer For-Schleifen-Funktion versucht, klappt aber auch nicht.

Code: Alles auswählen

import numpy as np
import random

#Funktion für Füllen von Sudokuarray Zahl für Zahl
def sudokuzahlfunktion (zeile,zahl,a,b,c,d,e,x):
    for i in sudokuarray [zeile,:9]:
        i = np.isin(zahl,sudokuarray [zeile,:9]) and np.isin(zahl,sudokuarray[:,a]) and np.isin(zahl, sudokuarray[d:e,b:c])
        if i == False:
            sudokuarray [zeile,x] = zahl
        
def sudokuzahlfunktion1 (zeile,zahl,a,b,c,d,e,x):
    i = np.isin(zahl,sudokuarray [zeile,:9]) and np.isin(zahl,sudokuarray[:,a]) and np.isin(zahl, sudokuarray[d:e,b:c])
    if i == False:
        sudokuarray [zeile,x] = zahl
    
        
        
#Erzeugt Array 9x9
sudokuarray = np.zeros(shape=(9,9))


#Definition der Funktionsparameter
zeile = 0
zahl = random.randrange(1,10)
a = 0 
b = 0
c = 3
d = 0
e = 3
x = 0


wiederholungen = 0
while wiederholungen < 9:
    sudokuzahlfunktion1 (zeile,zahl,a,b,c,d,e,x)
    a = a + 1
    if wiederholungen == 3 or wiederholungen == 6:
        b = b+3
        c = c+3
    x = x + 1
    zeile = 0
    zahl = random.randrange(1,10) 
    wiederholungen = wiederholungen + 1
    
       
        
print (sudokuarray)
der kleine Fritz
User
Beiträge: 25
Registriert: Montag 18. Dezember 2023, 11:33

...hat sich erledigt... ich habs geschafft... natürlich or statt and ! :lol:
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@der kleine Fritz: Variablennamen sollten sprechend sein. a, b, c, d, e, x sind das nicht.
Man darf keine globalen Variablen benutzen.
In `sudokuzahlfunktion` wird im ersten for-Schleifendurchgang ein Wert nach Bedingung gesetzt, in allen weiteren ist die Bedingung immer nicht gegeben, es tut sich also nichts, die for-Schleife kann weg.
Man überschreibt keine Variablen mit semantisch anderer Bedeutung, Du überschreibst `i` (was besser sudokufeldspalte heißen sollte) mit `i` (das besser ist_der_wert_bereits_vorhanden heißen sollte). Ein freudiger Quell endloser Fehlersuche.
Mit False vergleicht man nicht explizit, sondern benutzt not.
Man muß nicht jedes Ergebnis an eine Variable binden.
np.isin ist einfach nur ein kompliziertes `wert in array`.
Funktionsnamen sollten sprechend sein, wenn der Name den Bestandteil "funktion" enthält dann ist irgendwas faul.
Das ganze sollte daher ungefähr so aussehen:

Code: Alles auswählen

def set_value_in_field_if_allowed(sudoku_field, value, row, column, test_column, block_row_start, block_column_start, block_row_end, block_column_end):
    if not (value in sudoku_field[row, :] or value in sudoku_field[:, test_column] or value in sudoku_field[block_row_start:block_row_end, block_column_start:block_column_end]):
        sudoku_field[row, column] = value
Jetzt fällt natürlich sofort auf, dass es zwar nur ein `row`-Argument gibt, aber zwei `column` bzw. `test_column`-Argumente. Warum prüfst Du, ob eine Zahl in der gleichen Spalte vorkommt, wie dort, wo Du sie eintragen willst, bei der Spalte unterscheidet sich das aber?

Beim Namen set_value_in_field_if_allowed fällt auch sofort auf, dass da zwei Dinge gemacht werden, die eigentlich getrennt gehören: Testen, ob eine Zahl in einer Zelle erlaubt ist, und das Eintragen der Zahl. Das sollten also zwei Funktionen sein.
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@der kleine Fritz: Die ``while``-Schleife im Hauptprogramm ist eigentlich eine ``for``-Schleife.

`wiederholungen`, `a`, und `x` haben in dieser Schleife immer den gleichen Wert. `d` und `e` haben ebenfalls immer den gleichen Wert der sich noch nicht einmal ändert. Die Werte von `b` und `c` unterscheiden sich immer um den Versatz 3, das heisst `c` kann man trivial aus `b` errechnen. Und `b` lässt sich seinerseits einfach aus `wiederholungen` (oder `a` oder `x`) berechnen.

`zeile` hat immer den Wert 0 und wird auch immer wieder erneut auf diesen Wert gesetzt.

Statt `zahl` einmal vor der Schleife und dann nach der Verwendung in der Schleife zu ermitteln, sollte diese Zeile nur *einmal* *in* der Schleife *vor* der Verwendung stehen. Da der Name nur für den Aufruf verwendet wird, braucht man das Ergebnis auch gar nicht an einen Namen binden. Und ich würde da `randint()` statt `randrange()` verwenden.

Code: Alles auswählen

zeile = 0
zahl = random.randrange(1,10)
a = 0 
b = 0
c = 3
d = 0
e = 3
x = 0

wiederholungen = 0
while wiederholungen < 9:
    sudokuzahlfunktion1(zeile, zahl, a, b, c, d, e, x)
    a = a + 1
    if wiederholungen == 3 or wiederholungen == 6:
        b = b + 3
        c = c + 3
    x = x + 1
    zeile = 0
    zahl = random.randrange(1,10) 
    wiederholungen = wiederholungen + 1

# Schrumpft zusammen auf:

for i in range(9):
    b = i // 3 * 3
    sudokuzahlfunktion1(0, random.randint(1, 9), i, b, b + 3, 0, 3, i)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
der kleine Fritz
User
Beiträge: 25
Registriert: Montag 18. Dezember 2023, 11:33

@blackjack:

Ohh Mann das unterscheidet den Informatiker vom Hobby-Programmierer! Danke für den guten Tipp!
Antworten