Fehler bei leerer Liste bei min(liste)

Django, Flask, Bottle, WSGI, CGI…
Antworten
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Damit meine Würfelchen hier nur dort stehen, wo sie ein Fundament haben, musste ich einen komplizierten Code schreiben.
Bild
Dazu muss ich den kleinsten Wert in einer Liste bestimmen. Wenn die Liste leer ist, bekomme ich einen Fehler - kann ich das vermeiden?
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Was meinst Du von "Fundament"? Und welcher komplizierte Code?

Zur Frage: in dem Du prüfst, ob die Liste leer ist.
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Ich hatte es mit if liste probiert, aber mich anscheinend vertippt. Jetzt scheint es zu funktionieren.
Zur Frage:
Die Würfelchen werden mit Zufallszahlen erzeugt und da kann ja kein Würfelchen in der Luft hängen. Mit dem Code habe ich mir ziemlich einen abgebrochen - ob er aber elegant ist, wage ich zu bezweifeln. Willst du ihn wirklich sehen?

Code: Alles auswählen

            titel = "Räumliches Vorstellungsvermägen"
            text = "Ups, bei diesem Würfel sind ein paar Bausteine verlorengegeangen.<br>Wieviele sind es?"
            hilfe = ""
            anmerkung = ""
            h_hoehe = 200
            h_breite = 200
            h_n = 6
            t_n = h_n
            v_n = h_n
            start_x = int(h_breite/2) - h_n*10 + t_n*3
            start_y = int(h_hoehe/2) + v_n*10 - t_n*3
            liste = []
            soll = (h_n-1) * (t_n-1) * (v_n-1)
            ist = 0
            for n in range(1, h_n):
                liste.append(n)
                liste.append(n)
            schieb = []
            fehlt_v = []                                            #Liste mit den fehlenden Klötzchen in der vorderen Reihe
            fehlt_r =[]                                             #Liste mit den fehlenden Klötzchen in der rechten Reihe
            for v in range(1, v_n-1):
                for t in range(1, t_n):
                    for h in range(1, h_n):
                        if v == v_n-2 and t == t_n-1:               #sorgt für fehlende Klötzchen in der vorderen Reihe der vorletzten Schicht
                            zuza = random.randint(1,10)
                            if zuza < 8:
                                schieb.append((h*20+start_x-int(t*20*0.3), start_y+t*6-v*20))
                                ist += 1
                            else:
                                fehlt_v.append(h)
                        else:
                            if v == v_n-2 and h == h_n-1:           #sorgt für fehlende Klötzchen in der rechten Reihe der vorletzten Schicht
                                zuza = random.randint(1,10)
                                if zuza < 5:
                                    schieb.append((h*20+start_x-int(t*20*0.3), start_y+t*6-v*20))  
                                    ist += 1
                                else:
                                    fehlt_r.append(t)
                            else:
                                schieb.append((h*20+start_x-int(t*20*0.3), start_y+t*6-v*20))
                                ist += 1
            if fehlt_r:
                fehlt_r_min = fehlt_r[0]
            else:
                fehlt_r_min = 1
            for t in range(1, h_n):
                random.shuffle(liste)  
                list=set(liste[:h_n-2])
                for h in (list):
                    if t < t_n-1 or (h>0 and h not in fehlt_v):
                        if h < h_n-1 or (t < fehlt_r_min):
                            schieb.append((h*20+start_x-int(t*20*0.3), start_y+t*6-(v_n-1)*20))
                            ist += 1                          
            erg = (soll-ist)  
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

`min` hat das gewünschte Verhalten schon eingebaut.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Kommentare sollten beschreiben, was der Code macht. Wenn man sie außerhalb des rechten Randes des Editors versteckt, dann sind sie wenig hilfreich. Deshalb schreibt man Kommentare immer in der Zeile vor der, die sie beschreiben soll.
Die Berechnung der Würfelposition tauch vier mal im Code auf, was nicht nur schlecht ist, weil sich hier eine Rechnung wiederholt, sondern auch, weil sie den Code schwer lesbar macht, weil man immer wieder die selbe komplizierte Rechnung lesen und verstehen muß.
Eine Funktion sollte nur eine Sache machen, also entweder Würfel auswürfeln oder die Position von Würfeln berechnen.
Dann sollte man Dinge erst dann brechenen, wenn man sie auch braucht, und nicht viele Zeilen davor, wie bei `liste` oder `soll`. `ist` ist einfach nur die Länge der Liste `schieb` also ist das unnötig, selbst mitzuzählen.

Ohne irgend was am Algorithmus verändert zu haben, wirkt der Code schon viel strukturierter:

Code: Alles auswählen

    titel = "Räumliches Vorstellungsvermägen"
    text = "Ups, bei diesem Würfel sind ein paar Bausteine verlorengegeangen.<br>Wieviele sind es?"
    hilfe = ""
    anmerkung = ""
    h_n = 6
    t_n = h_n
    v_n = h_n
    schieb = []
    # Liste mit den fehlenden Klötzchen in der vorderen Reihe
    fehlt_v = []
    # Liste mit den fehlenden Klötzchen in der rechten Reihe
    fehlt_r =[]
    for v in range(1, v_n-1):
        for t in range(1, t_n):
            for h in range(1, h_n):
                # sorgt für fehlende Klötzchen in der vorderen Reihe der vorletzten Schicht
                if v == v_n-2 and t == t_n-1:
                    zuza = random.randint(1,10)
                    if zuza < 8:
                        schieb.append((h, t, v))
                    else:
                        fehlt_v.append(h)
                else:
                    # sorgt für fehlende Klötzchen in der rechten Reihe der vorletzten Schicht
                    if v == v_n-2 and h == h_n-1:
                        zuza = random.randint(1,10)
                        if zuza < 5:
                            schieb.append((h, t, v))
                        else:
                            fehlt_r.append(t)
                    else:
                        schieb.append((h, t, v))
    if fehlt_r:
        fehlt_r_min = fehlt_r[0]
    else:
        fehlt_r_min = 1


    liste = []
    for n in range(1, h_n):
        liste.append(n)
        liste.append(n)
    for t in range(1, h_n):
        random.shuffle(liste)  
        list=set(liste[:h_n-2])
        for h in list:
            if t < t_n-1 or (h>0 and h not in fehlt_v):
                if h < h_n-1 or (t < fehlt_r_min):
                    schieb.append((h, t, v_n))

    h_hoehe = 200
    h_breite = 200
    start_x = int(h_breite/2) - h_n*10 + t_n*3
    start_y = int(h_hoehe/2) + v_n*10 - t_n*3
    schieb_positionen = [
        (h * 20 + start_x - int(t * 20 * 0.3), start_y + t * 6 - v * 20)
        for h, t, v in schieb
    ]
    soll = (h_n-1) * (t_n-1) * (v_n-1)
    ergebnis = soll - len(schieb)
Ein Set `list` zu nennen, ist aus vielerlei Dingen schlecht. `list` ist der eingebaute Datentyp und sollte nicht durch Variablennamen überdeckt werden. Typen sollten keine Variablennamen sein, vor allem keine falschen.
Der nächste Punkt sind wieder schlechte Variablennamen. h_n, t_n, v_n sollten wohl besser anzahl_wuerfel_in_der_hoehe_plus_eins oder kurz anzahl_hoehe_plus_eins, anzahl_tiefe_plus_eins, anzahl_breite_plus_eins. Entscheiden hier ist, dass Du das plus_eins unterschlagen hast. Ohne das, wundert sich jeder, warum da eine 6 steht, obwohl doch nur fünf Würfel da sind. Ähnliches Problem sind Deine Zufallszahlen (zuza? wirklich?) Mit welcher Wahrscheinlichkeit ist eine Zahl zwischen 1 und 10 kleiner als 5? 40%, also wieder eins daneben.
Da dieses Mißverständnis eine große Fehlerquelle gilt es als erstes, das plus_eins loszuwerden:

Code: Alles auswählen

    titel = "Räumliches Vorstellungsvermägen"
    text = "Ups, bei diesem Würfel sind ein paar Bausteine verlorengegeangen.<br>Wieviele sind es?"
    hilfe = ""
    anmerkung = ""
    anzahl_breite = 5
    anzahl_tiefe = anzahl_breite
    anzahl_hoehe = anzahl_breite
    schieb = []
    # Liste mit den fehlenden Klötzchen in der vorderen Reihe
    fehlt_v = []
    # Liste mit den fehlenden Klötzchen in der rechten Reihe
    fehlt_r =[]
    for v in range(anzahl_hoehe - 1):
        for t in range(anzahl_tiefe):
            for h in range(anzahl_breite):
                # sorgt für fehlende Klötzchen in der vorderen Reihe der vorletzten Schicht
                if v == anzahl_hoehe - 2 and t == anzahl_tiefe - 1:
                    if random.random() < 0.7:
                        schieb.append((h, t, v))
                    else:
                        fehlt_v.append(h)
                # sorgt für fehlende Klötzchen in der rechten Reihe der vorletzten Schicht
                elif v == anzahl_hoehe - 2 and h == anzahl_breite - 1:
                    if random.random() < 0.4:
                        schieb.append((h, t, v))
                    else:
                        fehlt_r.append(t)
                else:
                    schieb.append((h, t, v))

    if fehlt_r:
        fehlt_r_min = fehlt_r[0]
    else:
        fehlt_r_min = 0

    liste = list(range(anzahl_breite)) * 2
    for t in range(anzahl_breite):
        random.shuffle(liste)  
        positionen = set(liste[:anzahl_breite - 1])
        for h in positionen:
            if t < anzahl_tiefe - 1 or (h >= 0 and h not in fehlt_v):
                if h < anzahl_breite - 1 or (t < fehlt_r_min):
                    schieb.append((h, t, anzahl_hoehe))

    hoehe = 200
    breite = 200
    start_x = int(breite/2) - anzahl_breite * 10 + anzahl_tiefe * 3 + 7
    start_y = int(hoehe/2) + anzahl_hoehe * 10 - anzahl_tiefe * 3 - 7
    schieb_positionen = [
        (h * 20 + start_x - int(t * 20 * 0.3), start_y + t * 6 - v * 20)
        for h, t, v in schieb
    ]
    soll = anzahl_breite * anzahl_tiefe * anzahl_hoehe
    ergebnis = soll - len(schieb)
An manchen Stellen scheinst Du Breite und Tiefe verwechselt zu haben. Und im letzten Teil scheint die Höhe eins zu hoch zu sein.
Was hast Du Dir beim mittleren Teil mit der Liste `liste` gedacht? Irgendwie habe ich das Gefühl da steckt wieder eine einfache Wahrscheinlichkeit dahinter. Ohne Erklärung versteht man das nicht.

Code: Alles auswählen

    for t in range(anzahl_tiefe):
        for h in range(anzahl_breite):
            if ((t == anzahl_tiefe - 1 and h in fehlt_v)
                or (h == anzahl_breite - 1 and t >= fehlt_r_min)):
                pass
            elif random.random() < 0.666667:
                schieb.append((h, t, anzahl_hoehe - 1))
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Gute Güte - hast du dich da wirklich reingeschafft? Dann sollte ich mir wirklich beim Benennen von Variablen und beim Kommentieren mehr Mühe geben.
Ich stelle immer wieder fest, dass es mir schwer fällt, komplexere Codes zu entwickeln und schreibe oft halt noch, wie ich das von Basic kenne, Zeile für Zeile. Das mit dem

Code: Alles auswählen

        (h * 20 + start_x - int(t * 20 * 0.3), start_y + t * 6 - v * 20)
        for h, t, v in schieb
    ]
ist ja wirklich viel einfacher - so Sachen muss ich unbedingt lernen. Das mit der Anzahl der Würfelchen war mir nicht so wichtig, ändere ich aber und das mit den Zufallszahlen habe ich einfach ausprobiert, bis es mir gefallen hat, da war mir der tatsächliche Wert nicht so wichtig.

Das mit der Liste in der Mitte ist mir nicht besser eingefallen (ich war aber ganz stolz, dass ich das irgendwie hinbekommen habe.
Diese Routine berechnet die Würfelchen im obersten Stockwerk:
Zuerst eine Liste mit den doppelten Zahlen bis zur maximalen Breite:
[1, 1, 2, 2, 3, 3, 4, 4, 5, 5]
... dann sortiere ich diese Liste in jeder Reihe zufällig neu:
[3, 5, 1, 2, 4, 2, 3, 4, 5, 1]
...und wähle dann die ersten (hier) vier aus und sorge mit "set" dafür, dass keine Zahl doppelt ist:
{1, 2, 3, 5}
... in dieser Zeile werden dann die Würfelchen 1, 2, 3 und 5 gezeichent und
dann kommt die nächste Reihe:
[5, 3, 2, 1, 4, 1, 4, 5, 2, 3]
{1, 2, 3, 5}
[1, 4, 3, 3, 2, 1, 5, 2, 4, 5]
{1, 3, 4}
[1, 3, 3, 5, 5, 2, 4, 1, 2, 4]
{1, 3, 5}
[4, 5, 3, 4, 1, 2, 1, 3, 2, 5]
{3, 4, 5}
Und später muss vorm Zeichnen noch überprüfen, ob ein Klötzchen drunter da ist. Bei der rechten Seite wollte ich, dass auch kein Klötzchen vor einer Lücke steht.
Besser kann ich das nicht :( .
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Nochmals Danke! Ich habe alles eingebaut, geht prima!
(ich saß mehrere Tage an dem Code - wie lange hast du denn für die Verbesserungen gebraucht?)
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Code verändern ist ja deutlich einfacher, als Code von Grund auf zu entwickeln.

Für guten Code braucht es aber gute Vorbereitung. Bei Dir ist es einmal das Problem genau zu beschreiben. Du hast zwei Ebenen, die vorletzte Ebene soll an den Rändern fehlende Würfel haben, und eine letzte Ebene mit zusätzlich an zufälligen Stellen fehlenden Würfeln:

Code: Alles auswählen

    second_last_plane = [
        [
            (t == anzahl_tiefe - 1 and random.random() >= 0.7)
            or (v == anzahl_breite - 1 and random.random() >= 0.4)
            for h in range(anzahl_breite)
        ] for t in range(anzahl_tiefe)
    ]
    last_plane = [
        [
            missing or random.random() >= 2/3
            for missing in row
        ] for row in second_last_plane
    ]
Und noch der Code zum Umwandeln dieser Listen in die eigentlichen Würfelpositionen:

Code: Alles auswählen

    hoehe = 200
    breite = 200
    start_x = breite // 2 - anzahl_breite * 10 + anzahl_tiefe * 3 + 7
    start_y = hoehe // 2 + anzahl_hoehe * 10 - anzahl_tiefe * 3 - 7
    full_plane = [[False] * anzahl_breite] * anzahl_tiefe
    schieb_positionen = [
        (start_x + h * 20 - t * 6, start_y + t * 6 - v * 20)
        for v, plane in enumerate([full_plane] * (anzahl_hoehe - 2) + [second_last_plane, last_plane])
        for t, row in enumerate(plane)
        for h, missing in enumerate(row)
        if not missing
    ]
    soll = anzahl_breite * anzahl_tiefe * anzahl_hoehe
    ergebnis = soll - len(schieb_positionen)
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Ich bin schwer beeindruckt. Konntest du sowas von Anfang an oder anders gefragt: Kann man das lernen? Sieht toll aus und ich vermute, du hast das einfach so geschrieben, ohne es ausprobiert zu haben. ... Es funktioniert auf Anhieb!
Leider verstehe ich höchstens Ansätze von deinem Code. Wahrscheinlich ist das auch der Grund warum ich in Schach verliere und auch in meinem Mathestudium nicht so erfogreich war. Ich fürchte, ich muss weiter kleine Brötchen backen und meine Programme "linear" schreiben. Siehst du eine Möglichkeit mir auf die Sprünge zu helfen wie das funktioniert?
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Der Trick ist, viel zu üben. Nach dreißig Jahren fällt einem das dann einfacher.
Was konkret verstehst Du daran nicht?
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Machst du das auch beruflich?

Also ich habe mir mal die Listen anzeigen lassen. Die erste (second-last_plane) verstehe ich (einigermaßen) die erste Liste besteht aus False/True für die Reihen in der vorletzten Schicht.
Bei der zweite Schleife (last_plane), steht "missing" für "false" in der ersten Liste?
Wofür steht "False" in "full_plane = [[False] * anzahl_breite] * anzahl_tiefe"?
Und wie funktioniert "for v, plane in enumerate([full_plane] * (anzahl_hoehe - 2) + [second_last_plane, last_plane])"?

Und dann noch die Variable: "v" ist nicht definiert und erzeugt eine Fehlermeldung und "h" scheint nicht genutzt zu werden. (Ich hatte h als horizontal (Breite) und v als vertikal (Höhe) gedacht - und t als Tiefe).

Ach, wenn ich schon am Frage stellen bin: Du kennst ja mein Projekt. In meinem OpenOffice Programm, sieht man, wie die Klötzchen nacheinander "aufgebaut" werden - das gefällt mir und macht die Aufgabe nachvollziehbar. Das könnte man ja sicher auch als Animation in svg nachstellen. Aber was ich noch nicht verstanden habe: Mal angenommen, mir gelingt es, irgendwann meinen Rechentrainer zu veröffentlichen, und mehrere Schülerinnen und Schüler greifen gleichzeitig auf diese Aufgabe zu, macht das Performanceprobleme?
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn `v` nicht definiert ist, `h` aber nicht benutzt wird, dann wird das ein trivialer Tippfehler sein, der bei einbuchstabigen Variablennamen vorkommen kann und mir eingerutscht ist, weil ich zum Schluß noch versucht habe, da irgendeine Konsistenz reinzubringen.

Bei komplizierten Ausdrücken hilft es, die auseinander zu nehmen, hier also:

Code: Alles auswählen

    full_cube = [full_plane] * (anzahl_hoehe - 2) + [second_last_plane, last_plane]
    schieb_positionen = [
        (start_x + h * 20 - t * 6, start_y + t * 6 - v * 20)
        for v, plane in enumerate(full_cube)
        for t, row in enumerate(plane)
        for h, missing in enumerate(row)
        if not missing
    ]
und der Variablenname dient auch gleichzeitig der Dokumentation, was denn der Sinn des Konstrukts ist.

Jetzt willst Du also auch noch animierte svg-Dateien schreiben. Ja, das geht auch, weil css Animationen unterstützt. Und diese Animation läuft ja auf dem Rechner der Schüler, die einzigen mit Performance-Problemen macht also der Browser Deiner Schüler.
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Sirius3 hat geschrieben: Donnerstag 18. August 2022, 21:25 Der Trick ist, viel zu üben. Nach dreißig Jahren fällt einem das dann einfacher.
Ich beschäftige mich ja erst seit Januar diesen Jahres mit dem Thema - vielleicht ist da ja noch Hoffnung. Aber in 30 Jahren werde ich 98!
(Vielleicht sagt jetzt ja mal jemand zur Aufmunterung, dass das für 8 Moante ja schon ganz gut geht und dass ich die Hoffnung nicht aufgeben soll :) .)
Sirius3 hat geschrieben: Freitag 19. August 2022, 07:58 Wenn `v` nicht definiert ist, `h` aber nicht benutzt wird, dann wird das ein trivialer Tippfehler sein
... erstaunlicherweise funktioniert es aber auch so.
Sirius3 hat geschrieben: Freitag 19. August 2022, 07:58 Und diese Animation läuft ja auf dem Rechner der Schüler, die einzigen mit Performance-Problemen macht also der Browser Deiner Schüler.
... hätte ich (ausnahmsweise) vor dem Posten nachgedacht, hätte ich eigentlich auch selbst drauf kommen können!
Benutzeravatar
Dennis89
User
Beiträge: 1123
Registriert: Freitag 11. Dezember 2020, 15:13

Pitwheazle hat geschrieben: Samstag 20. August 2022, 15:21 (Vielleicht sagt jetzt ja mal jemand zur Aufmunterung, dass das für 8 Moante ja schon ganz gut geht und dass ich die Hoffnung nicht aufgeben soll :) .)
Für 8 Monate geht das ja schon ganz gut, geb die Hoffnung nicht auf 🧐


SCNR
"When I got the music, I got a place to go" [Rancid, 1993]
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Dennis89 hat geschrieben: Samstag 20. August 2022, 18:59 Für 8 Monate geht das ja schon ganz gut, geb die Hoffnung nicht auf 🧐
Das ist sehr lieb von dir, danke schön.
SCNR
Antworten