Zdefiniuj procedurę KWADRATY :lista rysującą na ekranie ciąg kwadratów. Dana :lista jest listą list. Każdy element danej :lista jest listą pustą lub listą jednoelementową zbudowaną analogicznie, tj. też jest listą pustą lub jednoelementową. Liczba elementów danej :lista określa liczbę rysowanych kwadratów. Każdy kwadrat może zawierać wewnętrzne kwadraty, zależnie od poziomu zagłębień listy opisującej kwadrat. Odstępy pomiędzy współśrodkowymi kwadratami są takie same i równe długości boku najmniejszego z nich. Długości boków wszystkich zewnętrznych kwadratów są takie same i możliwie duże, tak żeby wszystkie kwadraty mieściły się na ekranie. Odstępy pomiędzy sąsiednimi zewnętrznymi kwadratami są równe jednej piątej długości boku zewnętrznych kwadratów.
Przykładowe wywołania:
Zadanie zostanie podzielone na trzy mniejsze zadania. Pierwsze z nich będzie dotyczyć rysowania kwadratu o zadanym boku o środku tam gdzie stoi żółw. Drugą funkcją pomocniczą będzie funkcja, która policzy ile razy jest lista zagnieżdżona w liście. Innymi słowy ile będzie kwadratów do narysowania w danej iteracji. Z kolei główna funkcja korzystając z obydwu narysuje wskazany w zadaniu rysunek.
Poniższą funkcję pozostawiam bez komentarza, ponieważ składa się z elementarnych części rysowania.
Do rozwiązania tego problemu warto wykorzystać rekurencję.
(2.) Po wywołaniu sprawdzamy przekazany argument. Jeśli element jest pusty to znaczy, że dana lista nie ma już więcej podlist. (3.) Wtedy należy zwrócić jeden. (5.) Jednak jeśli przekazany argument ma chociaż jeden element to zwracamy sumę 1 oraz głębokość przekazując do kolejnego wywołania pierwszy element listy :el.
Określ maksymalną (2.) szerokość i (3.) wysokość rysunku. (4.) Pobierz długość listy - wygodniej będzie dalej używać dwuliterej zmiennej niż całego sformułowania. (5.) Oblicz długość na podstawie maksymalnej szerokości. Należy pamiętać, żeby uwzględnić przerwy pomiędzy kwadratami równymi szerokości kwadratu podzielonej na pięć. (6.) Upewnij się, że bok kwadratu nie wszedł większy niż maksymalna wysokość rysunku. Jeśli tak to (7.) zmień długość kwadratu na wysokość rysunku.
(9. - 12.) Rysowanie rozpoczynamy od przejścia na środek lewego kwadratu. (13.) Dla każdego elementu na liście głównej: (14.) policz ile pobrany element ma list w liście. (15.) Na tej podstawie wylicz szerokość najmniejszego kwadratu. (16. - 18.) Narysuj wszystkien :n kwadratów. Na koniec każdej iteracji (19. - 22.)przesuń na środek kwadratu obok.
Zdefiniuj funkcję KK :gra, której daną jest niepusta lista dziewięcioliterowych słów. Każde słowo opisuje układ kółek i krzyżyków w popularnej grze "kółko i krzyżyk" na planszy 3 na 3 pola - wierszami (tzn. trzy pierwsze znaki opisują pierwszy wiersz planszy, itd.). W słowach mogą występować tylko małe litery x, o oraz w. Oznaczają one: x - krzyżyk na danym polu, o - kółko na danym polu, zaś w - wolne pole. Zakładamy poprawność danych słów, tzn. każde z nich opisuje możliwy układ w czasie gry. Zakładamy także, że żadne ze słów nie opisuje sekwencji wygrywającej.
Wartością funkcji KK jest prawda, jeśli dana lista :gra opisuje możliwą sekwencję kolejnych układów w czasie gry, zaś fałsz - w przeciwnym przypadku.
KK [xwxoxooww] | prawda |
---|---|
KK [xwxoxooww xwxoxooxw xwxoxooxo] | prawda |
KK [wwxoxooww xwxoxooxw] | fałsz |
KK [wwwwwwwww wwwwxwwww owwwxwwww oxwwxwwww] | prawda |
Początkowo zadanie może wydawać się nieco skomplikowane, ale warto zauważyć, że wymienione układy są poprawne. Potem warto się zastanowić kiedy kolejne układy na planszy będą prawidłowe. Najprostszy warunek jest taki, że pomiędzy dwoma kolejnymi układami na planszy zaszła dokładnie jedna zmiana wartości pól. Drugi warunek polega na sprawdzeniu, który z graczy się ruszył. Jeśli ten sam gracz wykonał dwa razy z rzędu ruch to układy nie mogą opisywać realnego stanu gry.
W rozwiązaniu nie zostały ujęte jeszcze dwa warunki: przede wszystkim należałoby sprawdzić czy w każdym następnym układzie zmniejsza się liczba wolnych pól. Jeśli nie to znaczy, że przy przejściu do kolejnego układu zmieniany jest znak na zajętym polu.
Funkcja KK_roznic szuka różnic pomiędzy przekazanymi argumentami :a i :b jako wynik zwraca listę elementów różnych elementów dodają na listę tylko element z listy :b.
(2.) Początkowo lista musi być pusta. (3.) Dla każdego elementu w układzie planszy: (4.) Jeśli elementy są różne to (5.) dodaj do listy element z listy :b. (8.) Na koniec zwróć utworzoną listę.
(2.) Na początek należy stwierdzić, że niewiadomo kto ostatni wykonał ruch. (W niektórych układach początkowych można to stwierdzić porównując ilość x oraz o). (3.) Dla każdej kolejnej pary układów na podanej liście :gra: (4.) pobierz listę różnych elementów. Następnie (5.) sprawdź czy lista ma długość 1. Fałsz będzie oznaczał, że nie doszło do jakiejkolwiek zmiany na planszy, albo więcej niż jedno pole zostało zmienione. W takim przypadku (6.) przerwij funkcję zwracając fałsz. (8.) Fałsz należy też (9.) zwrócić jeśli w poprzedniej kolejce ten sam gracz wykonał ruch. (11.) Na koniec każdej iteracji zamień, który gracz ostatnio wykonał ruch. (13.) Jeśli funkcja nie zostanie przerwana to zwróć prawdę.
Zdefiniuj funkcję DESZYFR :zaszyfr :klucz1 :klucz2, której danymi są:
Wynikiem funkcji jest lista zawierająca wszystkie możliwe słowa, które po zaszyfrowaniu dają :zaszyfr. Kolejność słów w wyniku jest nieistotna. Przyjęty sposób szyfrowania to modyfikacja jednego z najstarszych znanych systemów kodowania, przypisywanego Juliuszowi Cezarowi. Polega on na zastąpieniu każdej kolejnej litery - literą występującą w alfabecie o określoną liczbę pozycji dalej, cyklicznie (tj. jeśli wykraczamy poza alfabet, to kolejne litery bierzemy z początku alfabetu). W naszym zadaniu tę liczbę pozycji, oddzielnie dla samogłosek i spółgłosek, określają klucze szyfrowania funkcji DESZYFR.
DESZYFR "fycmqva 2 2 | [dwakoty] |
---|---|
DESZYFR "epi 4 3 | [ame amf bme bmf] |
Na początek warto dokładnie przeanalizować skąd biorą się wyrazy, które po zaszyfrowaniu mogą być podanym wyrazem. Przede wszystkim każdy znak mógł zostać zaszyfrowany po zamiania samogłoski lub spółgłoski, dlatego istnieje możliwość, że są dwa różne sposoby zapisu danej pozycji szyfrowanego słowa. Jednak jeśli litera została zaszyfrowana poprzez zamianę samogłoski to po deszyfrowaniu kluczem musi być samogłoską, a nie spółgłoską. Analogiczne rozumowanie dla spółgłosek.
Funkcja sprawdzająca czy znak jest samogłoską wygląda następująco:
W celu usprawnienia działania fłównej funkcji warto napisać funkcję, która będzie deszyfrować znak na podstawie klucza:
Początkowo rozwiązanie może wydawać się nieuintycyjne, ale uwzględnia wiele różnych przypadków, które mogłoby dać nieprzewidziane wyniki w innych implementacjach:
(2.) Na początek deklarujemy pustą liste. (3.) Dla każdej litery w zaszyfrowanym słowie: (4.) deklarujemy kolejną pustą listę, która przechowa wszystkie możliwe wyjściowe znaki danego znaku. (5.) Pobieramy kolejny element z słowa i zapisujemy do zmiennej :el. (6.) Jeśli po deszyfrowaniu :klucz1 wyjdzie samogłoska to (7.) należy ją dopisać na listę :listael. (9.) Analogicznie dla spółgłosek: jeśli po deszyfrowaniu :el :klucz2 wyjdzie spógłoska (czyli nie samogłoska) to (10.) należy ją dodać na :listael.
Na tym etapie :listaael może pusta. (12.) W takim przypadku należy: (13.) zwrócić pustą listę jako wynik całej funkcji, ponieważ dany znak nie mógł zostać zaszyfrowany przy pomoc ani jednego klucza. (15.) Jeśli jednak istnieje choć jeden znak na liście to (15.) deklarujemy pustą nową listę wynikową. (16.) Jeśli dotychczasowa lista wynikowa była pusta to oznacza, że dopiero sprawdzamy pierwszy znak. Wtedy (17. - 20.) wystarczy przepisać elementy z :listaael do :lista_nowa.
Jednak, gdy już lista coś zawiera to znaczy, że przeglądamy nie pierwszy znak. Wtedy (22.) dla każdej możliwej litery przy deszyfrowaniu: (23.) pobieramy ten element i (24. - 27) tworzymy z nim wszystkie możliwe teksty z tekstami na dotychczasowj liście wynikowej. (30.) Na koniec nową listę ustlamy jako końcową listę :lista. Po przejrzeniu wszystkich elementów (32.) należy zwrócić :lista.
Zdefiniuj funkcję LKS :słowo, której daną jest słowo składające się z małych liter alfabetu łacińskiego i cyfr. Wynikiem funkcji jest lista, której kolejne elementy odpowiadają kolejnym znakom danej. Litery kodujemy listami: literę a - listą pustą, literę b - listą składającą się z listy pustej, literę c - listą [[[]]], itd. według pozycji poszczególnych liter w alfabecie. Cyfry danej :słowo są bezpośrednio umieszczane w wyniku - bez kodowania.
Oto przykładowe wyniki:
LKS "c3ba | [[[[]]] 3 [[]] []] |
---|---|
LKS "a37ba | [[] 3 7 [[]] []] |
LKS "d | [[[[[]]]]] |
(2.) Początkowo lista wynikowa jest pusta. Potem (3.) dla każdego elementu słowa: (4.) pobieramy kolejny element. (5.) Jeśli nie jest cyfrą to (6.) zamieniamy go na listę list przy pomocy funkcji pomocniczej. (8.) Niezależnie od tego co znajduje się w :el dopisujemy go na listę wynikową. Po zakończeniu pętli (10.) zwracamy listę :w.
Funkcja działa rekurencyjnie. (2.) Jeśli wykryje, że kodowany jest znak "a to zwróci (3.) pustą listę. Jednak dla każdej innej litery (5.) zwróci listę, która będzie zawierać listę dla znaku wcześniejszego w alfabecie. W ten sposób rekurencja zawsze będzie zbiegać do litery "a, a więc będzie skończona. W przypadku wywołania procedury dla znaku o numerze ASCII poniżej 97 program może zwrócić różne wyniki.