Procedury

Programowanie w logo polega na opisywaniu czynności wykonywanych przez żółwia za pomocą procedur zrozumiałych dla żółwia.

Procedury bez parametrów

Najprostsze czynności zostały zdefiniowane przez twórców języka logo. Nazywamy je procedurami pierwotnymi. Niektóre z nich już poznałeś (na przykład np, ws, cs pw czy lw). Obszerną listę procedur pierwotnych znajdziesz w dziale słowniczek. Wykorzystując istniejące procedury możesz budować własne, odpowiadające chwilowym potrzebom programów.

Definicję procedury rozpoczynasz od słowa oto. Następnie podaj nazwę procedury (nie może ona zawierać spacji), potem dodaj treść procedury. Koniec sygnalizujesz słowem już.

Aby zdefiniować procedurę wywołujesz edytor procedur poleceniem red (redaguj). Możesz po słowie red wpisać nazwę procedury (np. red "kwadrat), albo możesz to zrobić później.

oto nazwa_procedury
treść procedury
już

Jak to działa? Spróbuj zdefiniować sobie procedurę rysującą kwadrat o boku 100 pikseli.

oto kwadrat
powtórz 4 [ np 100 pw 90 ]
już

Teraz wystarczy wywołać procedurę... kwadrat ...i na ekranie pojawi się żądany kwadrat.

Zadeklarowany w ten sposób każdy rysowany kwadrat będzie miał bok długości 100 pikseli. Jeżeli będziesz potrzebował do rysowania innego kwadratu, np. o boku 20 punktów, będziesz musiał zdefiniować nową procedurę pod nową nazwą:

oto kwadrat20
powtórz 4 [ np 20 pw 90 ]
już

W ten sposób możesz zdefiniować także inne figury, np. koło czy trójkąt.

oto trójkąt
powtórz 3 [ np 100 pw 120 ]
już

Procedury z parametrami

Zauważ, że definiowanie procedury bez parametru jest mało elastyczne. Właściwie do każdej potrzebnej nam figury będziesz potrzebował nowej procedury. Żeby narysować poniższy rysunek, musiałbyś zdefiniować 10 różnych procedur kwadratów o bokach od 20 do 200 punktów!

Znacznie lepiej byłoby zdefiniować jedną uniwersalną procedurę, która sprawdzałaby się każdej sytuacji. Struktura takiej procedury wygląda następująco:

oto nazwa_procedury :parametr1 :parametr2 itd.
treść procedury
już

Spróbuj teraz zdefiniować procedurę, w której parametrem będzie długość boku kwadratu:

oto kwadrat :bok
powtórz 4 [np :bok pw 90]
już

Teraz wystarczy wywołanie: kwadrat 70 i już kwadrat o boku 70 pojawi się na Twoim ekranie.

Parametrem Twojej procedury jest :bok. Nazwa poprzedzona jest : (dwukropkiem), który nazywamy operatorem wartościowania. Będziesz go stosował, aby odróżnić nazwę parametru (bądź zmiennej) od nazwy procedury.

Spójrz i wypróbuj także poniższe procedury. Pierwsza narysuje na ekranie koło o zadanym promieniu, druga wielobok o określonym przy wywoływaniu boku i liczbie kątów.

Dlaczego takie skomplikowane obliczenia przy kole? Otóż obwód 36-boku równy jest 36 * długość boku. Natomiast obwód koła równy jest 2 * Pi * r. Przyrównajmy te dwie wartości do siebie:

2 * Pi * r = 36 * bok

Znając promień otrzymujemy:

bok = (2 * Pi * r) / 36 ~= 0,175 * r

oto koło :promień
powtórz 36 [np :promień * 0,175 pw 10]
już
oto wielokfor :bok :ilebok powtórz :ilebok [np :bok pw 360 / :ilebok] już

Przyjrzyjmy się procedurze określającej wielokąt foremny (wielokfor). Pozwala ona zdefiniować dowolny wielokąt foremny. Nie musimy definiować osobno kwadratu, trójkąta równobocznego, pięciokąta foremnego itd. To co ma być narysowane zależy od parametru :ilebok. Żółw rysujący wielokąt dokonuje obrotu o 360°. Stąd też (ze względu na równość wszystkich kątów wielokąta foremnego) po narysowaniu jednego boku obraca się o kąt 360°/:ilebok.

Podobnie jeśli chcemy rysować czworokąty typu: równoległobok, romb, prostokąt, kwadrat, możemy zdefiniować równoległobok, a reszta zależy od wartości parametrów.

oto równoległobok :boka :bokb :alfa
powtórz 2 [np :boka pw :alfa np :bokb pw 180 - :alfa]
już

I tak na pierwszym rysunku mamy wywołania równoległobok 100 200 50 i równoległobok 150 150 60,

a na drugim równoległobok 100 200 90 i równoległobok 150 150 90

Na ogół tworzymy procedury z parametrem, ponieważ często je wykorzystujemy do tworzenia innych, bardziej skomplikowanych. Jednak czasem z treści zadania wynika, że procedura ma być wywoływana bez parametru. Jak szybko przerobić procedurę z parametrem na procedurę bez parametru?

Można to zrobić na kilka sposobów. Jednym z nich jest użycie polecenia niech. Oto przykład

procedura z parametrem

oto kwadrat :bok
powtórz 4 [np :bok pw 90]
już

procedura bez parametru

oto kwadrat
niech "bok 100
powtórz 4 [np :bok pw 90]
już

Polecenie niech tworzy w procedurze kwadrat zmienną o nazwie bok (nazwę poprzedzamy znakiem dosłowności ") i nadaje mu wartość 100. Jeśli chcemy zmienić długość boku wystarczy przypisać zmiennej nową wartość. No tak, ale czy nie prościej jest w procedurze kwadrat zastąpić zmienną liczbą 100 lub inną?

W tym przypadku zgoda, ale jeśli procedura jest dłuższa to narażamy się na konieczność dokonywania wielu zmian. Łatwo więc o pomyłkę.

Dialog z użytkownikiem

Użytkownik, który będzie chciał wywołać daną procedurę często nie jest zorientowany jakie wartości parametrów powinien podać (np. zbyt duże powodują, że rysunek nie mieści się na ekranie, lub, że elementy są zbyt małe). Dlatego możemy tworzyć procedury bezparametrowe, a użytkownika poinformować o zakresie wpisywanych liczb. Oto najprostszy przykład

oto kwadrat
PISZ [Podaj długość boku kwadratu w pikselach!]
PISZ [Powinna to być liczba od 50 do 300]
niech "bok csw
powtórz 4 [np :bok pw 90]
już

Użyte tutaj csw oznacza czytaj słowo. Po wpisaniu wartości należy nacisnąć klawisz Enter.

W przypadku gdy mamy kilka parametrów możemy je wprowadzać jeden po drugim lub użytkownik wpisuje wszystkie oddzielone spacjami. W treści procedury musi być wtedy polecenie czytaj listę.

oto równoległobok
PISZ [Podaj kolejno długości boków i wielkość kąta.]
PISZ [Boki powinny być liczbami od 50 do 300]
PISZ [a kąt od 20 do 80.]
niech "x cl
niech "boka pierw :x
niech "bokb pierw bp :x
niech "alfa pierw bp bp :x
powtórz 2 [np :boka pw :alfa np :bokb pw 180 - :alfa]
już

Jak widać skorzystaliśmy tutaj jeszcze z procedur pierwotnych dotyczących list. Po wczytaniu listy musimy ją podzielić na 3 części. Polecenie pierw oznacza pierwszy element listy (pierwsza wpisana liczba), a polecenie bp bez pierwszego elementu (w tym przypadku listy) czyli bez pierwszej wpisanej liczby. Jak widać zmiennej :boka przypisano pierwszy element listy, zmiennej :bokb - drugi element listy (liczba wpisana jako druga) i zmiennej :alfa - trzeci element listy (trzecia wpisana liczba).

Możemy to zagadnienie rozwiązać tak jak w przypadku kwadratu

oto równoległobok
PISZ [Podaj kolejno długości boków i wielkość kąta.]
PISZ [Boki powinny być liczbami od 50 do 300]
PISZ [a kąt od 20 do 80.]
PISZ [Po wpisaniu każdej liczby naciśnij Enter.]
niech "boka csw
niech "bokb csw
niech "alfa csw
powtórz 2 [np :boka pw :alfa np :bokb pw 180 - :alfa]
już

Skoki, czyli przemieszczanie się po ekranie bez rysowania linii

Podczas rysowania często przemieszczamy żółwia po ekranie w trybie podniesionego pisaka. Zdarza się, że zapominamy o jego opuszczeniu, co powoduje wiele błędów w rysunkach. Warto korzystać z procedury pomocniczej, dzięki której żółw zmienia swoje położenie na ekranie nie rysując linii.

Proponujemy dwie takie procedury. Pierwszą o nazwie skok1 do skoku wzdłuż osi żółwia oraz skok2 do skoku wzdłuż osi żółwia i prostopadle do niej.

skok1

oto skok1 :a
pod
np :a
opu
już

Dodatnia wartość parametru :a powoduje skok żółwia w kierunku, w którym jest skierowany, a ujemna w przeciwnym.

skok2

oto skok2 :a :b
pod
np :a pw 90
np :b lw 90
opu
już

Pierwszy parametr (:a) jest odpowiedzialny za ruch w kierunku osi żółwia (dodatnia wartość naprzód, ujemna wstecz), drugi (:b) w kierunku prostopadłym względem kierunku patrzenia żółwia (dodatnia wartość w prawo, ujemna w lewo).

Powyższy rysunek pokazuje jak żółw przemieszcza się po ekranie. Wędruje on po bokach prostokąta (przerywana linia). Taki sposób sterowania żółwiem jest bardzo wygodny – wystarczy określić ile wynoszą te boki, aby dotarł on do wybranego punktu.

Jeśli żółw przemieszcza się tylko w kierunku prostopadłym względem kierunku patrzenia, to możemy skorzystać z procedury skok1 (pw 90 skok1 :a lw 90) lub z procedury skok2 (skok2 0 :a).

Opracowanie uzupełniające

W tym opracowaniu będą tylko opisy konkretnych procedur! Nie będzie żadnej teorii.

Jak zdefiniować (najprostszą figurę) kwadrat?

Ogólny sposób rysowania kwadratu.

Rysowanie kwadratu z konkretnymi danymi.

Jak widać na rysunku należy powtórzyć 4x następujące czynności:

np 100 pw 90

Wygląda ono tak, gdy użyjemy rozkazu "powtórz":

powtórz 4 [np 100 pw 90]

Żeby jednak powstał kwadrat, któremu możemy przypisywać dowolne długości boków, należy zdefiniować procedurę kwadrat:

oto kwadrat
PISZ [Podaj długość boku kwadratu w pikselach!]
niech "bok cz
powtórz 4 [np :bok pw 90]
już

Trójkąt równoboczny

Wykonujemy go w następujący sposób: powtórz 3 [np 100 pw 120]. Wielkość 100 - to długość boku trójkąta, a 120 to kąt obrotu żółwia.

A oto definicja procedury "trójkąt" równoboczny:

oto trójkąt :a
powtórz 3 [np :a pw 120]
już

Ale aby wyglądał tak jak na rysunku powyżej, należy wykonać drobną zmianę w procedurze:

oto trójkąt :a
pw 30
powtórz 3 [np :a pw 120]
już

Przyjrzyjmy się poniższym rysunkom, a powinno się wszystko wyjaśnić!

Wielokąt foremny

Zauważmy stałą własność podczas tworzenia dwóch wcześniejszych figur. Są oto figury foremne (mające jednakowej długości boki oraz takie same kąty). Spróbujmy utworzyć procedurę, która narysuje nam dowolny wielokąt foremny. (na rysunku widoczne są kąty o jakie skręca za każdym razem żółw po przebyciu naprzód :bok).

Założenia:

nazwa_procedury: wielokąt

parametry_procedury:

oto wielokąt :bok :jaki
powtórz :jaki [np :bok pw 360 / :jaki]
już

Zastanów się i zmodyfikuj procedurę w podobny sposób jak w definicji kwadratu, tzn. ma być wypisany komunikat, aby podać długość boku figury oraz co oto ma być za wielokąt? A dopiero po zatwierdzeniu powinien być czyszczony ekran i rysowany właściwy wielokąt foremny!

OBROTY figur

Aby rozpocząć definicję procedury obrotu musimy wiedzieć jaką figurę chcemy obracać? Załóżmy, że będzie oto wcześniej zdefiniowany trójkąt.

Napiszemy prostą procedurę z dwiema parametrami obracającą nasz trójkąt równoboczny. Zauważmy, że w trójkącie jest podany jeden parametr czyli długość boku trójkąta, nazwany jest on ":a". Musimy go też wprowadzić do deklaracji procedury "obrot", a także powinniśmy wprowadzić drugi parametr, który obróci nasz trójkąt - nazwijmy go ":kat".

oto obrot :a :kat         | :a - to długość boku, :kat - kąt
powtórz 3 [np :a pw 120]  | rysujemy nasz trójkąt
pw :kat                   | obracamy żółwia o :kat
powtórz 3 [np :a pw 120]  | rysujemy trójkąt
już                       | kończymy działanie procedury

Tak będzie wyglądał narysowany trójkąt i jego obrót: :a = 100, :kat = 66

ZADANIA do samodzielnego opracowania

Zadanie 1

Napisz procedurę "trojkat" ze zmienną :a rysującą figurę jak na rysunku z prawej strony.

Zadanie 2

Napisz procedurę "tr_rownoramienny" ze zmienną :a rysującą figurę jak na rysunku. Długość boku "c" widoczną na rysunku musisz obliczyć z twierdzenia Pitagorasa.

Zadanie 3

Napisz procedurę z dwoma parametrami :bok, :kat, rysującą figurę przedstawioną na rysunku.

Zadanie 4

Napisz procedurę "okno" ze zmienną :a rysującą figurę jak na rysunku.

Zadanie 5

Napisz procedurę, która będzie wykorzystywała wcześniejszą procedurę “WIELOKAT” i będzie go obracała tyle razy aby powstała taka figura jak na rysunku.

Zadanie 6

Napisz procedurę "figura" ze zmienną :a rysującą figurę jak na rysunku.