Turtle auf den sichtbaren Bildschirm begrenzen?

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.
Antworten
PatrickF
User
Beiträge: 27
Registriert: Sonntag 1. Mai 2022, 09:43

Hallo,

habe ein kleines Programm zum Turtle-experimentieren gebaut. Das zeichnet einfach Zufallsbilder:

Code: Alles auswählen

import turtle as tl
import random as rd
tl.speed(0)
tl.bgcolor("black")
farben=("Turquoise", "maroon", "green", "Goldenrod", "black", "white")
hoehe= 500
weite= 500
tl.screensize(weite, hoehe)

for i in range(0,10**10):
    length=rd.randint(1,20)
    rotate=rd.randint(0,360)
    tl.forward(length)
    tl.color(farben[rd.randint(0,5)])
    tl.right(rotate)
    penstate=rd.randint(0,5)
    if penstate==1:
        tl.penup()
        penstate="oben"
    else:
        tl.pendown()
        penstate="unten"
    print(f"Durchgang {i}, Pen: {penstate}")
turtle.hideturtle()
turtle.exitonclick()
Problem ist nur, dass die Turtle irgendwann die Canvas verlässt. Kann man das irgendwie mit wenig Aufwand verhindern bzw. die Turtle in einem Bereich auf der sichtbaren Canvas halten?

Schöne Grüße
Pf
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PatrickF: Naja, es wird ja nicht wirklich der Canvas verlassen, der ist ”unendlich” gross, sondern der Viewport. Du kannst nach jedem Schritt die Screensize abfragen und die Turtle-Position und prüfen ob die noch im Bereich von minus der halben Breite und der halben Breite ist und minus halbe Höhe und halbe Höhe, denn der Startpunkt 0,0 der Turtle ist in der Mitte vom Viewport.

Sonstige Anmerkungen: Die Modulnamen sollten nicht kryptisch abgekürzt werden. Bei den letzten Zeilen hast Du das auch vergessen, da wird `turtle` zu einer Ausnahme führen.

Wobei diese letzten beiden Zeilen Unsinn sind, denn bei 10 Milliarden Schleifendurchläufen und mindestens 1 Millisekunde pro Durchlauf ist diese Schleife nach fast 116 Tagen Laufzeit erst am Ende. Real noch länger wenn man tatsächlich eine Vektorgrafik mit 10 Milliarden Linien erstellen könnte, was praktisch deutlich früher in einem Speicherproblem enden wird. Also kann man da einfach eine Endlosschleife schreiben bis es halt kracht. Wenn man so etwas tatsächlich ”endlos” laufen lassen möchte, mit konstantem Speicherverbrauch und konstanter CPU-Last, darf man keine Vektorgrafik verwenden, sondern muss das pixelbasiert machen.

Das `weite` sollte wohl `breite` heissen. `rotate` sollte eher `angle` heissen. Und nicht von 0 bis 360 gehen, denn damit ist ein Winkel mit 0 und 360 zweimal vertreten, im Gegensatz zu allen anderen ganzzahligen Winkeln. Denn ob man sich 0 Grad oder 360 Grad dreht, kommt ja beides auf die gleiche Richtung hinaus.

Aus den Farben wählt man besser mit `random.choice()` aus.

Der Name `penstate` wird im gleichen Kontext mal an eine Zahl und mal an eine Zeichenkette gebunden. Man sollte Namen nicht so wiederverwenden, das ist verwirrend.

Es ist mir auch nicht ganz klar nach welchem Kriterium die 1 beim Vergleich ausgewählt wurde. Warum nicht 0, 2, 3, oder 4? Ich hätte da ja die 0 genommen, einfach weil es die erste ist. Beziehunsgweise den Code so geändert, das man mit `bool()` und gegebenenfalls ``not`` aus `penstate` einen Wahrheitswert macht. Wenn man den `pendown` nennt, hätte man den gleichen Namen den man mit der `pen()`-Funktion als Schlüsselwortargument setzen kann.

Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
import random
import turtle
from itertools import count

FARBEN = ["black", "goldenrod", "green", "maroon", "turquoise", "white"]
BREITE = HOEHE = 500


def main():
    turtle.speed(0)
    turtle.bgcolor("black")
    turtle.screensize(BREITE, HOEHE)

    for i in count():
        turtle.forward(random.randint(1, 20))
        turtle.color(random.choice(FARBEN))
        turtle.right(random.randint(0, 359))
        pendown = bool(random.randint(0, 5))
        turtle.pen(pendown=pendown)

        print(f"Durchgang {i}, Pen: {'unten' if pendown else 'oben'}")


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
PatrickF
User
Beiträge: 27
Registriert: Sonntag 1. Mai 2022, 09:43

Vielen lieben Dank erstmal für die ausführlichen Anmerkungen.

Die 10**10 hab ich einfach mal als 'ziemlich große Zahl' eingesetzt, einfach damit das mal eine Weile läuft. Mir fehlt aktuell noch eine Möglichkeit, den Durchlauf auf einen bestimmten Tastendruck zu beenden. Arbeite halt grad das Kapitel "Turtle" durch und spiele etwas rum.

Mit den 360° stimmt natürlich, wäre mir aber peinlicherweise nicht aufgefallen.

Die "1" bei pendown ist rein willkürlich, wollte einfach dass der Stift mal absetzt, aber nicht zu oft , deshalb hab ich einfach mal die Würfelwahrscheinlichkeit genommen, bekanntlich hätte es jede andere Zahl auch getan. Ev. vergrößere ich den Ereignisraum später noch. Alle Zeichenparameter sind ja experimentell.
Du kannst nach jedem Schritt die Screensize abfragen und die Turtle-Position und prüfen ob die noch im Bereich von minus der halben Breite und der halben Breite ist und minus halbe Höhe und halbe Höhe, denn der Startpunkt 0,0 der Turtle ist in der Mitte vom Viewport.
Ok ich schau mal ob ich das hinbekomme...

Grußies
Pf
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Abbruch per Tastendruck kann man beispielsweise über `onkey()` und eine Queue lösen wenn man sich noch um Objektorientierung und eine eigene Klasse drücken möchte:

Code: Alles auswählen

#!/usr/bin/env python3
import random
import turtle
from functools import partial
from itertools import count
from queue import Queue

FARBEN = ["black", "goldenrod", "green", "maroon", "turquoise", "white"]
BREITE = HOEHE = 500
QUIT_EVENT = object()


def main():
    turtle.speed(0)
    turtle.bgcolor("black")
    turtle.screensize(BREITE, HOEHE)

    queue = Queue()
    turtle.onkey(partial(queue.put, QUIT_EVENT), "q")
    turtle.listen()

    for i in count():
        if not queue.empty() and queue.get() is QUIT_EVENT:
            break

        turtle.forward(random.randint(1, 20))
        turtle.right(random.randint(0, 359))
        pendown = bool(random.randint(0, 5))
        turtle.pen(pendown=pendown, pencolor=random.choice(FARBEN))

        print(f"Durchgang {i}, Pen: {'unten' if pendown else 'oben'}")


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Code: Alles auswählen

#!/usr/bin/env python3
import random
import turtle
from functools import partial
from itertools import count
from queue import Queue

FARBEN = ["black", "goldenrod", "green", "maroon", "turquoise", "white"]
BREITE = HOEHE = 500
QUIT_EVENT = object()


def main():
    turtle.speed(0)
    turtle.bgcolor("black")
    turtle.screensize(BREITE, HOEHE)

    queue = Queue()
    turtle.onkey(partial(queue.put, QUIT_EVENT), "q")
    turtle.listen()

    for i in count():
        if not queue.empty() and queue.get() is QUIT_EVENT:
            break

        turtle.forward(random.randint(1, 20))
        turtle.right(random.randint(0, 359))
        pendown = bool(random.randint(0, 5))
        turtle.pen(pendown=pendown, pencolor=random.choice(FARBEN))

        x, y = turtle.position()
        
        if x < -BREITE / 2:
            x += BREITE
        elif x > BREITE / 2:
            x -= BREITE

        if y < -HOEHE / 2:
            y += HOEHE
        elif y > HOEHE / 2:
            y -= HOEHE

        pen_state = turtle.pen()
        turtle.penup()
        turtle.setposition(x, y)
        turtle.pen(pen_state)

        print(f"Durchgang {i}, Pen: {'unten' if pendown else 'oben'}")


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten