====== LAB: Praca z listami w Prologu (cz. 2) ====== ===== -. Zadania z list do samodzielnego rozwiązania ===== Korzystając z wiedzy zdobytej w [[listy1|pierwszej części laboratorium z listami]] proszę rozwiązać następujące problemy: - zdefiniować predykat, powodujący usunięcie 3 ostatnich elementów listy L, w wyniku powstaje lista L1, użyć ''sklej''. - zdefiniować predykat, powodujący usunięcie 3 pierwszych elementów listy L, w wyniku powstaje lista L1, użyć ''sklej''. - zdefiniować predykat, powodujący usunięcie 3 pierwszych i ostatnich elementów listy L, w wyniku powstaje lista L2, użyć ''sklej''. - zdefiniować parę komplementarnych predykatów ''nieparzysta(L)'' oraz ''parzysta(L)'' sprawdzajacych czy argument jest listą o odpowiednio nie/parzystej długości. * czy Twój predykat potrafi również **utworzyć** listę o zadanej parzystości? (jako argument podajemy niewiadomą, a nie stałą) - zdefiniować predykat ''palindrom(L)'', L jest palindromem, jeżeli czyta się tak samo od przodu i tyłu, np. ''[a,l,a]'', ''[m,a,d,a,m]''. (podpowiedź: można nie/użyć ''odwroc''.) - zdefiniować predykat ''przesun(L1,L2)'', gdzie L2, jest przesuniętą rotacyjnie o jeden element L1, np.: ?- przesun([1,2,3,4,5,6,7,8],X),przesun(X,Y),przesun(Y,Z). X = [2, 3, 4, 5, 6, 7, 8, 1] Y = [3, 4, 5, 6, 7, 8, 1, 2] Z = [4, 5, 6, 7, 8, 1, 2, 3] - zdefiniować predykat ''przeloz(L1,L2)'', który zamienia listę liczb (max. 0-9), na listę słów: ?- przeloz([1,4,7],X). X = [jeden, cztery, siedem] ; ?- przeloz(A,[dwa,osiem,zero]). A = [2, 8, 0] ; posługując się faktami: znaczy(0,zero). znaczy(1,jeden). znaczy(2,dwa). znaczy(3,trzy). znaczy(4,cztery). znaczy(5,piec). znaczy(6,szesc). znaczy(7,siedem). znaczy(8,osiem). znaczy(9,dziewiec). Podpowiedź: predykat ma być rekurencyjny. - zdefiniować predykat ''podzbior(L,Z)'', który sprawdza, czy Z zawiera się w L, oraz wypisuje wszystkie możliwe podzbiory L (jeżeli Z jest niewiadoma). ?- podzbior([a,b,c],[c]). Yes ?- podzbior([a,b,c],[a,c]). Yes ?- podzbior([a,b,c],X). X = [a, b, c] ; X = [a, b] ; X = [a, c] ; X = [a] ; X = [b, c] ; X = [b] ; X = [c] ; X = [] - zdefiniować predykat ''podziel(L,L1,L2)'', który dzieli listę L, na dwa fragmenty L1 i L2, mniej więcej równej długości (z dokładnością do jednego el.), np.: ?- podziel([],X,Y). X = [] Y = [] ; ?- podziel([1],X,Y). X = [1] Y = [] ; ?- podziel([1,2],X,Y). X = [1] Y = [2] ; ?- podziel([1,2,3],X,Y). X = [1, 3] Y = [2] ; ?- podziel([1,2,3,4],X,Y). X = [1, 3] Y = [2, 4] ; ?- podziel([1,2,3,4,5],X,Y). X = [1, 3, 5] Y = [2, 4] ; ?- podziel([1,2,3,4,5,6,7,8],X,Y). X = [1, 3, 5, 7] Y = [2, 4, 6, 8] ; - zdefiniować predykat ''splaszcz'', który zamienia dowolnie zagnieżdżoną listę, w listę płaską (której el. nie są listami). (podstawowe rozwiązanie działa bez nawrotów - nie należy naciskać '';'') ?- splaszcz([[a],b,c],X). X = [a, b, c] ?- splaszcz([[a],[b,[d]],c],X). X = [a, b, d, c] ?- splaszcz([a,b,c],X). X = [a, b, c] ?- splaszcz(a,X). X = [a] - Napisz program który obliczy na jakie monety można rozmienić zadaną sumę pieniędzy. * Zdefiniuj nominały monet: np. ''moneta(1)'' oznacza monetę jednozłotową, * Predykat rozmieniający powinien mieć dwa argumenty: ''rozmien/2'', gdzie pierwszy to kwota, a drugi lista nominałów monet na jakie można rozmienić kwotę; uwaga: predykat będzie niedeterministyczny. ===== -. Przechwytywanie wyników ===== Z Prologiem dostarczonych jest kilka predykatów przydatnych przy obróbce wyników wyszukiwania. Predykat //bagof/3//, użyty jako ''bagof(X,P,L)'' buduje listę ''L'', złożoną z takich ''X'', że spełnione jest ''P''. Podobnie działa //setof/3//, jednak powstała lista jest posortowana i nie zawiera ew. duplikatów. Specjalny operator ''^'' pozwala na modyfikowanie zapytania i jest równoważny kwantyfikacji egzystencjalnej, np. zakładając istnienie bazy faktów zdefiniowanej za pomocą predykatu ''a/2'': * ''bagof(X,Y^a(X,Y),L)'' spowoduje znalezienie listy L na ktorej beda znajdować się wartości X niezależnie od tego jaką wartość przyjmuje Y (dokładnie jedno rozwiązanie). * ''bagof(X,a(X,Y),L)'' spowoduje znalezienie listy L na ktorej beda znajdować się wartości X dla konkretnej (znalezionej) wartości Y (wiele rozwiązań, lista dla każdej wartości Y). FIXME: składnia z ^ nie działa (w zainst. wersji SWI), jeżeli jest użyta jako cel w powłoce SWI - należy zdefiniować odpowiedni predykat jej używający w pliku. Predykat //findall/3// wymusza wyszukanie wszystkich możliwych wyników. **Ćwiczenie:** Wczytać program z 1. zajęć {{rodzina1.pl}} Sprawdzić działanie: ?- rodzic(X,robert). ?- bagof(X,rodzic(X,robert),L). Sprawdzić działanie: ?- bagof(X,ojciec(tomek,X),L). ?- setof(X,ojciec(tomek,X),L). Następnie: ?- bagof(X,Y^ojciec(X,Y),L). ?- setof(X,Y^ojciec(X,Y),L). Oraz: ?- bagof(X,ojciec(X,Y),L). ?- findall(X,ojciec(X,Y),L). ===== -. Labirynt ===== Dany jest program poszukujacy drogi w labiryncie: {{:pl:prolog:prolog_lab:maze.pl|}}. Proces poszukiwania uruchamiany jest za pomocą predykatu ''solve_maze/''. Głównym predykatem definiujacym algortym poszukiwania jest ''path/2''. Labirynt znajduje się na ponumerowanych polach. Połączenia pomiędzy polami, którymi można przejść zdefiniowane są za pomocą predykatu ''connect/2''. Wejście do labiryntu oznaczone jest ''start'', wyjście: ''finish''. Poniższy przykład definoiuje bardzo prosty labirynt. connect(start,1). connect(1,2). connect(2,3). connect(2,4). connect(3,finish). **Ćwiczenie:** 1. Przeanalizuj program {{maze.pl}}. Do czego służy predykat ''connected_to/2''? 2. Napisz odpowiednie klauzule predykatu ''connect/2'' dla labiryntu danego na rysunku poniżej oraz uruchom program poszukujący drogi. {{:pl:prolog:prolog_lab:maze.jpg}} 3. Zmodyfikuj labirynt, tak aby do wyjścia prowadziła więcej niż jedna droga. Czy ''solve_maze/0'' znajdzie więcej niż jedną drogę? Czy ''path/2'' znajdzie więcej niż jedną drogę? ===== -. Zagadka ===== Na blokach piramidek (patrz rysunki) należy umieścić cyfry od 1 do 9. W niebieskich rzędach cyfry muszą być różne, w żółtych - mogą się powtarzać, a w różowych - przynajmniej jedna powtórka jest obowiązkowa. Każda cyfra (poza umieszczonymi w podstawie) musi być sumą **lub** różnicą dwu cyfr znajdujących się bezpośrednio pod nią. Część liczb jest już na swoich miejscach. Napisz program w Prologu, który poda rozwiązania piramidek. Wskazówka: Przeczytaj //"helpa"// do predykatu //list_to_set/2//. Może się okazać przydatny... {{:pl:prolog:prolog_lab:zagadka-1.png|Zagadka 1}} {{:pl:prolog:prolog_lab:zagadka-2.png|Zagadka 2}} ===== Komentarze ===== Z braku lepszego miejsca tutaj studenci wpisują komentarze natury ogólnej do tego lab. 8-) --- //[[gjn@agh.edu.pl|Grzegorz J. Nalepa]] 2008/02/20 14:34//