Strona główna » Poradniki » Logomocja » LOGIA » Logia 1996/97 - Etap II
 

Logia 1996/97 - Etap II

· Etap I · Etap II · Etap III ·
iOryginalna treść zadań jest dostępna pod oficjalnym adresem konkursu LOGIA

Zadanie 1

Rysunki wyglądają podobnie, ale różnią się stopniem złożoności. Napisz procedurę RYS :n z jednym parametrem, która dla danej wartości parametru :n - określającej stopień złożoności rysunku - równej: 1, 2, 3, 4, ... tworzy na środku ekranu możliwie duży rysunek, odpowiednio taki jak na rysunkach poniżej.

Zadanie warto podzielić na mniejsze fragmenty. W ten sposób kod stanie się bardziej przejrzysty. Zauważmy, że rysunek składa się z 13 takich samych symboli - rysowaniem tego zajmie się funkcja RYS. Każdy symbol składa się z czterech identycznych części obróconych o 90 stopni - to będzie rysować RYS_kwa, a ostatnią część jeden z czterech części narysuje RYS_pom. Kod należy zacząć pisać od ostatniej procedury jako, że reszta na niej polega. Procedura będzie przyjmować dwa argumenty: :n - złożoność elementu oraz :w - długość najmniejszego kwadratu w elemencie.

  1. oto RYS_pom :n :w
  2.   powtórz (:n)[
  3.     np :w
  4.     pw 90
  5.     np (2*(npw - 1) + 1)*:w
  6.     pw 90
  7.     np (2*(npw - 1) + 1)*:w
  8.     pw 90
  9.     np :w
  10.     pw 90
  11.     np 2*(npw - 1)*:w
  12.     lw 90
  13.     np 2*(npw - 1)*:w
  14.     pw 90
  15.     pod
  16.     np :w*2
  17.     opu
  18.   ]
  19.   pod
  20.   ws :w*(:n*2)
  21.   opu
  22. już

(2.) Rozpoczynamy rysowanie :n elementów (3. - 14.). Warto zauważyć, że nawet kwadrat może być narysowany tak samo jak reszta elementów. W pierwszej iteracji całkowicie pomija się rysowanie krawędzi, które są od strony kwadratu co daje kwadrat. (15. - 17.) Przesuwamy żółwia, aby narysował kolejny pod element. Na koniec (19. - 21.) wracamy tam skąd zaczęliśmy rysować.

Klena funkcja RYS_kwa ma za zadanie narysować pełny symbol przy pomocy RYS_pom. Przyjmujemy, że żółw przed i po narysowaniu znajduje się w środku symbolu, dlatego:

  1. oto RYS_kwa :n :h
  2.   pod
  3.   ws :h/2
  4.   pw 90
  5.   ws :h/2
  6.   lw 90
  7.   opu
  8.   powtórz 4[
  9.     RYS_pom :n :h/(4*:n - 1)
  10.     pod
  11.     np :h
  12.     pw 90
  13.     opu
  14.   ]
  15.   pod
  16.   np :h/2
  17.   pw 90
  18.   np :h/2
  19.   lw 90
  20.   opu
  21. już

(1.) Przyjmowany argument :h określa całkowitą wysokość symbolu. (2. - 7.) przesuwamy żółwia w lewy dolny róg symbolu. (8.) Cztery razy rysujemy: (9.) elementy podając odpowiednie wartości argumentów, a nastepnie (10. - 13.) odpowiednio ustawiając żółwia, aby mógł narysować kolejny element. Na sam koniec (15. - 20.) wracamy tam skąd rozpoczeliśmy rysowanie symbolu.

Mając już napisane dwie funkcje pomocnicze napisanie głównej funkcji RYS jest znacznie prostsze. Kod wygląda następująco:

  1. oto RYS :n
  2.   niech "h 400
  3.   niech "margin :h/(8*:n+9)
  4.   pod
  5.   ws :h/2
  6.   pw 90
  7.   ws :h/2
  8.   lw 90
  9.   opu
  10.   powtórz 4[
  11.       np :h
  12.       pw 90
  13.   ]
  14.   pod
  15.   pw 90
  16.   np :margin*(:n+1.5)
  17.   lw 90
  18.   np :margin*(:n+1.5)
  19.   opu
  20.   powtórz 4[
  21.     powtórz 3[
  22.       RYS_kwa :n :margin*(2*:n+1)
  23.       pod
  24.       np :margin*(2*:n+2)
  25.       opu
  26.     ]
  27.     pw 90
  28.   ]
  29.   wróć
  30.   RYS_kwa :n :margin*(4*:n+3)
  31.  
  32. już

(2.) Ustalamy maksymalną wysokość rysunku. (3.) Wyliczamy zmienną :margin. Jest to odległość pomiędzy dwoma sąsiednimi symbolami. Jej wartość to gługość najmniejszego kwadratu w mniejszym symbolu. Na początek (4. - 13.) rysujemy obramowanie, a następnie (14. - 19.)przechodzimy na środek symbolu w lewym dolnym rogu i (20. - 28.) rysujemy dwanaście mniejszych symboli. Na koniec, aby szybko zakończyć funkcję (29.) wracamyna środek rysunku i (30.) rysujemy największy symbol.

Zadanie 2

Wynik serii rzutów monety można zapisać w postaci słowa utworzonego z małych liter alfabetu: o - orzeł oraz r - reszka. Np. zapisem serii pięciu rzutów: (orzeł, reszka, reszka, orzeł, reszka) jest pięcioliterowe słowo - orror.

Zdefiniuj funkcję MLKO :zsr, której wartością dla danego słowa będącego zapisem serii rzutów, jest maksymalna liczba kolejnych orłów w tej serii. Poniżej przedstawiamy przykładowe wyniki:

MLKO "rorrooooorrrroooorrrma wartość 5
MLKO "rrrrrma wartość 0
MLKO "ma wartość 0
MLKO "rorororoma wartość 1

Zauważmy, że sprawdzając każdą kolejną literę w przypadku znalezienia litery o możemy zwiększyć licznik. Jeśli napotkamy literę r można ustalić licznik na 0, ponieważ będzie trzeba zacząć zliczać litery o od nowa. Warto pamiętać, że kiedy napotkmamy literę wtedy wartość licznika jest największa. Wtedy należałoby sprawdzić czy licznik nie jest większy od wcześniej wyliczonego maksimum. Tego typu metoda ma wadą w przypadku słów, które mają na koniec same litery o. Wtedy ostatnia wartość licznika nie będzie uwzględniona. Można to poprawić dodając na koniec słowa literę r. Tego typu rozwiązanie przedstawia poniższy kod:

  1. oto MLKO :zsr
  2.   niech "zsr słowo :zsr "r
  3.   niech "max 0
  4.   niech "licznik 0
  5.   powtórz (długość :zsr)[
  6.     jeżeli(element npw :zsr = "o)[
  7.       zwiększ "licznik
  8.     ][
  9.       jeśli (:licznik > :max)[
  10.         niech "max :licznik
  11.       ]
  12.       niech "licznik 0
  13.     ]
  14.   ]
  15.   wynik :max
  16. już

(2.) Dodajemy na koniec słowa literę r. (3.) Ustalamy maksymalną liczbę liter o z rzędu na 0 oraz (4.) licznik na 0. (5.) Dla każdego znaku w słowie: (6.) sprawdzamy czy jest literą o. Jeśli tak to (7.) tylko zwiększamy licznik. W przeciwnym razie (9. - 11.) przypisujemy max nową wartość jeśli jest mniejsze od licznik i (12.) zerujemy licznik. (15.) Po zakończeniu pętli zwracamy zmienną :max.

Zadanie 3

Przesunięciem cyklicznym w prawo - w skrócie PCP - nazywamy funkcję, której wartością jest dane (niepuste) słowo z przestawionym ostatnim znakiem na początek. Jeśli dane słowo jest puste, to wartość PCP jest nieokreślona. Oto przykłady wyników:

PCP "abcdma wartość "dabc
PCP "ama wartość "a

Przesunięciem cyklicznym w lewo - w skrócie PCL - nazywamy funkcję, której wartością jest dane (niepuste) słowo z przestawionym pierwszym znakiem na koniec. Jeśli dane słowo jest puste, to wartość PCL jest nieokreślona. Oto przykłady wyników:

PCL "abcdma wartość "bcda
PCL "ama wartość "a

Ustalamy następujący system kodowania niepustych słów - dla danego klucza k= ..., -2, -1, 0, 1, 2, 3, ... kodem danego słowa jest:

  • wynik k-krotnego przesunięcia danego słowa w lewo, jeśli k<0,
  • wynik k-krotnego przesunięcia danego słowa w prawo, jeśli k>0,
  • dane słowo, jeśli k=0.

Zdefiniuj funkcję z dwoma parametrami KOD :k :s, której wartością dla danego klucza :k jest kod danego słowa :s zgodny z ustalonymi wyżej regułami. Poniżej przedstawiamy przykładowe wyniki:

KOD 2 "abcdema wartość "deabc
KOD -2 "abcdema wartość "cdeab
KOD 0 "abcdema wartość "abcde
KOD 7 "abcdema wartość "deabc

Uwaga: Nie musisz definiować funkcji PCL i PCP, tylko funkcję KOD i ewentualnie jakie sam(a) zechcesz funkcje pomocnicze.

Zadanie można napisać przy użyciu funkcji nak i nap. Tego typu rozwiązanie polegałoby na przesuwaniu pierwszej / ostatniej litery |:n| razy. Jednak tego typu rozwiązanie jest mało optymalne. Lepszym rozwiazaniem jest wybrać po kolei odpowiednie litery i z nich utworzyć tekst wynikowy. Ten pomysł realizuje poniższy kod:

  1. oto KOD :k :s
  2.   niech "w "
  3.   powtórz (długość :s)[
  4.     niech "w nak element ((mod (npw - 1 - :k) (długość :s)) + 1) :s :w
  5.   ]
  6.   wynik :w
  7. już

(2.) Tworzymy zmienną do której będziemy dopisywać kolejne literki. (3.) Tyle ile jest liter: (4.) wybieramy kolejne litery ze słowa :s i (6.) zwracamy wynik, czyli zmienną :w.