Żółwie przemieszczające się losowo

Załóżmy, że chcielibyśmy się zabawić oglądając żółwie chodzące po ekranie w sposób przypadkowy. Gdy uruchomimy już nasz program, to będziemy chcieli, żeby żółwie oraz sam program zachowywali się w następujący sposób:

  1. Żółw startuje ze środka ekranu.
  2. Rzucamy monetą. Jeżeli otrzymamy orła to obracamy się o 90 stopni w prawo. Jeżeli wypadnie reszka to obróć się w prawo o 90 stopni.
  3. Przejdź 50 kroków do przodu.
  4. Jeżeli żółw wyjdzie poza ekran to go zatrzymujemy, w innym przypadku wracamy do kroku 2 i powtarzamy.

Zauważmy, że nie możemy przewidzieć, ile razy żółw będzie musiał rzucić monetą zanim nie wyjdzie za ekran, więc nie do końca możemy użyć pętli for w tym przypadku. Tak naprawdę może się zdarzyć taka sytuacja, choć nie jest zbyt prawdopodobna, że program nigdy nie zakończy pracy, dlatego też będziemy używać owej niezdefiniowanej iteracji.

Tak więc bazując na powyższym opisie problemu, możemy podać następujący schemat programu:

stwórz okno oraz żółwia

dopóki żółw jest wciąż w obrębie okna:
    wygeneruj losowo 0 lub 1
    if liczba == 0 (orzeł):
        skręć w lewo
    else:
        skręć w prawo
    przejdź żółwiem 50 kroków w przód

W tym momencie jedyną rzeczą, która może być nie do końca jasna to jak sprawdzić czy żółw wciąż jest w obrębie okna. Ale jeżeli chodzi o programowanie to fajne jest to, że trudne rzeczy możemy odłożyć na później, a chwilowo zastosować cokolwiek co będzie działać od razu. Zrobimy to tak, że decyzję o tym, czy żółw wciąż jest na ekranie, czy może już go opuścił, zostawimy funkcji logicznej. Funkcję tą nazwiemy is_in_screen. Funkcję tą możemy zaimplementować tak, by po prostu zawsze zwracała True lub by decydowała losowo. Chodzi o to, by funkcja była prosta tak byśmy mogli skupić się na rzeczach które już znamy i jesteśmy w stanie dobrze zaprogramować. Jako, że funkcja zawsze zwracająca prawdę nie była by za dobrym rozwiązaniem napiszemy wersję decydującą losowo. Powiedzmy, że mamy 90% szans na to, że żółw wciąż jest w oknie, zatem pozostaje 10% na to, że żółw opuścił okno.




(iter_randwalk1)

Mamy teraz działający program, który rysuje błądzenie losowe żółwia z 90-cio procentową szansą na pozostanie na ekranie. Jesteśmy o tyle w dobrym położeniu, że większa część naszego programu już działa a my możemy skupić się na dalszej części programu – zdecydować czy żółw jest w obrębie ekranu czy nie.

Szerokość i wysokość ekranu możemy znaleźć używając metod odpowiednio window_width oraz window_height należących do obiektu screen. Musimy jednak pamiętać, że żółw zaczyna na pozycji 0,0 oznaczającej środek ekranu. Oznacza to, że chcemy żeby żółw poszedł dalej niż szerokość/2 (width/2) w prawo lub -szerokość/2 (-width/2) w lewo. Podobnie nie chcemy by żółw poszedł dalej niż wysokość/2 (height/2) w górę lub -wysokość/2 (-height/2) w dół. Jak już znamy wartości brzegowe możemy użyć wyrażeń warunkowych aby sprawdzić położenie żółwia względem brzegów i zwrócić False jeżeli żółw jest poza lub True jeżeli jest w środku ekranu. Oto nasza implementacja:

def is_in_screen(wn,t):
    leftBound = -(wn.window_width() / 2)
    rightBound = wn.window_width() / 2
    topBound = wn.window_height() / 2
    bottomBound = -(wn.window_height() / 2)

    turtleX = t.xcor()
    turtleY = t.ycor()

    stillIn = True
    if turtleX > rightBound or turtleX < leftBound:
        stillIn = False
    if turtleY > topBound or turtleY < bottomBound:
        stillIn = False

    return stillIn

Warunki możemy zapisać na wiele sposobów. Tutaj do zmiennej stillIn przypisaliśmy domyślną wartość True i użyliśmy dwóch instrukcji warunkowych if by ewentualnie zmienić wartość stillIn na False. Możecie przepisać ten kod używając zagnieżdżonych instrukcji warunkowych lub użyć konstrukcji elif oraz przypisać wartość True w klauzuli else.

Oto i pełna wersja programu realizującego błądzenie losowe żółwia.




(iter_randwalk2)

Moglibyśmy napisać ten program bez używania funkcji logicznej. Możecie spróbować przepisać powyższy program używając złożonej instrukcji warunkowej w pętli while. Użycie funkcji logicznej czyni program znacznie bardziej czytelnym i zrozumiałym. Daje nam również narzędzie do sprawdzania czy żółw nadal jest w obrębie ekranu, które można użyć w innej części programu gdybyśmy musieli. Kolejną korzyścią płynącą z takiej implementacji jest to, że jeżeli kiedykolwiek mielibyśmy napisać podobny program, możemy użyć tej właśnie funkcji gdy tylko będziemy jej potrzebować. Podzielenie całego programu na elementy jest również kolejnym przykładem dekompozycji funkcjonalnej.

Sprawdź swoją wiedzę

iter-4-1: Którą pętlę można użyć aby przeprowadzić następującą iterację: Wybieramy losowo dodatnią liczbę całkowitą a następnie drukujemy liczby od 1 do właśnie wybranej liczby włącznie.




iter-4-2: W programie realizującym błądzenie losowe widniejącym w tym rozdziale, co robi funkcja is_in_screen?





Następna część - The 3n + 1 Sequence