Laboratorul 6
(Deadline: 05.05.2019 23:59:59)
Daca nu sunteti logati exercitiile nu se mai afiseaza.
Module si bilioteci
Biblioteci din Sicstus Prolog
Se vor prezenta doar bibliotecile de care aveti nevoie in teme, dar daca sunteti interesati puteti vizualiza si lista completa de biblioteci oferite de Sicstus Prolog.
Biblotecile pe care le vom folosi:
Atentie, in cadrul laboratorului nu sunt explicate toate predicatele din bibliotecile mentionate mai sus, pe acestea este necesar sa le citit voi direct din documentatie. In cadrul laboratorului sunt mentionate doar predicatele cele mai importante si mai frecvent folosite prin teme (dar asta nu inseamna ca nu pot sa apara in teme si teste si din celelalte care nu apar in exemple)
Predicatele unei biblioteci se incarca prin predicatul use_module(library(nume_biblioteca)), de exemplu, in consola putem scrie:
% loading c:/documents and settings/userpc/desktop/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/random.po...
% module random imported into user
% loading c:/documents and settings/userpc/desktop/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/types.po...
% module types imported into random
% loaded c:/documents and settings/userpc/desktop/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/types.po in module types, 0 msec 536 bytes
% loading foreign resource c:/documents and settings/userpc/desktop/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/x86-win32-nt-4/random.dll in module random
% loaded c:/documents and settings/userpc/desktop/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/random.po in module random, 0 msec 12112 bytes
yes
| ?-
Atunci cand avem nevoie de predicatele unei biblioteci in cadrul unui program vom apela use_module cu bibliotecile necesare, printr-o directiva,
pentru ca incarcarea modulelor sa se faca in timpul consultarii programului, iar la inteogarea diverselor predicate din program sa avem deja
biblioteca incarcata.
Sa luam ca exemplu programul urmator in care se calculeaza suma a N numere random (iar numerele random se si afiseaza pe masura ce se genereaza).
%suma(+Nr,-Suma)
suma(0,0).
suma(N,S):-N>0, N1 is N-1, suma(N1,S1),
random(X),write(X),nl, S is S1+X.
consult('E:/schimbate_pe site/inteligenta artificiala 2013/exemplu_random_suma.pl').
% consulting e:/schimbate_pe site/inteligenta artificiala 2013/exemplu_random_suma.pl...
% loading c:/documents and settings/userpc/desktop/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/random.po...
% module random imported into user
% loading c:/documents and settings/userpc/desktop/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/types.po...
% module types imported into random
% loaded c:/documents and settings/userpc/desktop/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/types.po in module types, 0 msec 536 bytes
% loading foreign resource c:/documents and settings/userpc/desktop/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/x86-win32-nt-4/random.dll in module random
%% loaded c:/documents and settings/userpc/desktop/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/random.po in module random, 0 msec 12128 bytes
% consulted e:/schimbate_pe site/inteligenta artificiala 2013/exemplu_random_suma.pl in module user, 0 msec 12792 bytes
| ?- suma(3,S).
0.2163110752346893
0.6344657121210742
0.7621277925774055
S = 1.612904579933169 ?
yes
| ?-
Timp
Cateva predicate utile referitoare la data curenta ori la timestamp gasiti in biblioteca library(system).
Sa luam ca exemplu un program care calculeaza in cat timp se afiseaza numerele de la 0 la 5000.
scrie_nr(N,N).
scrie_nr(N,C):-C<N, C1 is C+1, write(C), write(' '), scrie_nr(N,C1).
durata_scriere(D):-now(D1), scrie_nr(5000,0), now(D2), D is D2-D1.
Generare numere random.
Se foloseste biblioteca library(random). Predicatul random(X), calculeaza in X un numar random in intervalul [0,1). Atentie, la intoarcerea in backtracking la reinterogarea lui random nu se intoarce un nou numar aleatorX = 0.2393746982829037 ? ;
no
| ?-
:-use_module(library(system)).
seteaza_seed:-now(X1), X is X1 mod 30000,
now(B),setrand(random(X,100,100,B)).
Fisiere si directoare
In biblioteca library(file_systems) veti intalni predicate cu care puteti manipula fisierele si directoarele(sa testati daca exista, sa le stergeti, sa le redenumiti).
De exemplu, puteti vedea care este working directory-ul:D = 'e:/schimbate_pe site/inteligenta artificiala 2013/' ?
yes
| ?-
yes
no
| ?- make_directory('piticei').
yes
| ?- directory_exists('piticei').
yes
| ?-
Se poate obtine lista cu fisierele dintr-un director. De exemplu pentru:
| ?- use_module(library(file_systems)).
% loading d:/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/file_systems.po...
% module file_systems imported into user
% module types imported into file_systems
% module system imported into file_systems
% loading d:/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/lists.po...
% module lists imported into file_systems
% module types imported into lists
% loaded d:/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/lists.po in module lists, 0 msec 45976 bytes
% loaded d:/sicstus prolog 4.0.2/sicstus prolog 4.0.2/library/file_systems.po in module file_systems, 47 msec 67928 bytes
yes
| ?- file_members_of_directory('D:/folder_test',L).
L = ['a.txt'-'d:/folder_test/a.txt','abc.txt'-'d:/folder_test/abc.txt','b.txt'-'d:/folder_test/b.txt','bau.txt'-'d:/folder_test/bau.txt','bzz.txt'-'d:/folder_test/bzz.txt','x.txt'-'d:/folder_test/x.txt','xyz.txt'-'d:/folder_test/xyz.txt'] ?
yes
| ?-
Executie in timp limitat
In unele cazuri avem nevoie sa oprim executia daca aceasta dureaza prea mult. Pentru aceasta vom folosi predicatul
time_out(:Scop,+Timp_ms,-Rezultat)
din biblioteca
library(timeout).
Asa cum e precizat in documentatie,
predicatul time_out porneste inteorgarea Scop, dar daca executia acesteia depaseste Timp_ms (masurat in milisecunde)
atunci se opreste executia si Rezultat va avea valoarea time_out, altfel, daca executia nu dureaza mai mult de
Timp_ms milisecunde aceasta se realizeaza cu succes iar in Rezultat e returnata chiar valoarea success.
Pentru a vedea un exemplu, consideram definit urmatorul predicat, care nu face altceva decat sa numere de la N pana la 0, afisand la final gata.
numara(N):-N>0,N1 is N-1,numara(N1).
gata
R = success ?
yes
| ?- time_out(numara(100000),100,R).
R = time_out ?
yes
| ?-
succes
. Pentru N=100000 insa dureaza mai mult de o secunda si time_out-ul opreste executia inainte ca predicatul
sa ajunga la sfarsit, instantiand R cu valoarea time_out
(adica a fost depasit timpul alocat).
Atentie, time_out pentru apeluri blocante precum read sau sleep nu va lua in considerare timpul de executie al acestora. In exemplul de mai jos, 3-ul s-a introdus dupa 2 secunde de la apel, si cu toate acestea time_out-ul a rezultat cu succes. In cel de-al doilea exemplu, sleep opreste executia pentru 2 secude insa time_out setat pe 1000 ms = 1 secunda in continuare rezulta in succes
|: 3.
R = success,
X = 3 ? yes
| ?- time_out((write(a),sleep(2),write(b)),1000,R).
ab
R = success ?
yes
| ?-
Definirea propriilor module se face foarte usor, puteti citi in documentatia Prolog despre acest lucru.
Probleme rezolvate folosind biblioteci
Numere random
Fapt aleator
Enuntul exercitiului. Se considera o baza de cunostinte cu niste castiguri posibile. Informatiile vor fi memorate in predicatul castig_posibil.
castig_posibil('neacastigator').
Se cere sa se scrie un predicat numit extrage_loz, care afiseaza un castig aleator (toate castigurile au aceeasi probabilitate) din baza de cunostinte. Dupa afisarea unui castig se va afisa si o intrebare "Mai doresti sa extragi un loz?". Daca utilizatorul raspunde "da", se afiseaza un nou castig si se repeta intrebarea. Daca utilizatorul raspunde "nu" (sau orice altceva), se termina executia predicatului.
castig_posibil(1).
castig_posibil(5).
castig_posibil(50).
castig_posibil(100).
castig_posibil(500).
Pentru ca avem nevoie de numere random, trebuie sa setam seed-ul pentru ele.
:-use_module(library(random)).
Observati ca setarea seed-ului s-a facut printr-o directiva, pentru a fi setat inaintea oricarei interogari:
:-use_module(library(system)).
:-seteaza_seed.
seteaza_seed:-now(X1), X is X1 mod 30000,
now(B),setrand(random(X,100,100,B)).
:-seteaza_seed.
Predicatul extrage_loz ar trebui sa aiba acces la lista posibilitatilor de extragere (obtinute din baza de cunostinte. Facem asta printr-un findall:
findall(Castig, castig_posibil(Castig),L)
Acum in lista L avem toate valorile din castig_posibil. Trebuie sa alegem un element aleator din lista. Facem asta folosind predicatul random_member(-Element, +Lista) care calculeaza in Element un element random din Lista.
random_member(Loz,L)
Urmeaza doar sa afisam eventualul castig, impreuna cu intrebarea pentru extragerea urmatoare, citind apoi raspunsul:
write(Loz),nl,
Daca raspunsul este "da", trebuie sa executam o noua extragere (apelam inca o data predicatul extrage_loz. Daca este alt raspuns, trebuie doar sa terminam predicatul cu succes.
write('Mai doresti sa extragi un loz?\n'),
read(X)
(X==da -> extrage_loz; true)
Avand in vedere cele explicate mai sus, iata si programul complet:
:-use_module(library(random)).
:-use_module(library(system)).
:-seteaza_seed.
seteaza_seed:-now(X1), X is X1 mod 30000,
now(B),setrand(random(X,100,100,B)).
castig_posibil('neacastigator').
castig_posibil(1).
castig_posibil(5).
castig_posibil(50).
castig_posibil(100).
castig_posibil(500).
extrage_loz:- findall(Castig, castig_posibil(Castig),L),
random_member(Loz,L),
write(Loz),nl,
write('Mai doresti sa extragi un loz?\n'),
read(X),
(X==da -> extrage_loz; true).
Un exemplu de executie ar fi:
| ?- extrage_loz.
neacastigator
Mai doresti sa extragi un loz?
|: da.
neacastigator
Mai doresti sa extragi un loz?
|: da.
100
Mai doresti sa extragi un loz?
|: da.
500
Mai doresti sa extragi un loz?
|: nu.
yes
| ?-
Matrice cu numere aleatoare
Enuntul exercitiului. Sa se scrie un predicat genereaza_matrice_random(+N,+A,+B,-M) care genereaza o matrice M de dimensiune N*N umpluta cu elemente aleatoare din intervalul [A,B).
Cum avem de lucrat cu numere aleatoare, primul lucru pe care il facem este setarea seed-ului:
:-use_module(library(random)).
:-use_module(library(system)).
:-seteaza_seed.
seteaza_seed:-now(X1), X is X1 mod 30000,
now(B),setrand(random(X,100,100,B)).
genereaza_matrice_random(N,A,B,M):- matrice_random(N,N,A,B,M).
Pentru a genera o matrice, stim ca trebuie sa avem un predicat care genereaza cate o linie. Acest predicat trebuie apelat la randul lui de un predicat care genereaza toate liniile (si care va fi de fapt matrice_random). Predicatul dupa fiecare generare de linii va scadea 1 din numarul de linii de generat. Deci evident trebuie testat inainte de a genera o linie daca numarul de linii de generat este mai mare decat 0.
matrice_random(NL,NC, A,B,[Linie|M]):- NL>0, linie_random(NC,A,B, Linie), NL1 is NL-1, matrice_random(NL1,NC,A,B,M).
Predicatul linie_random(NC,A,B, Linie) este cel care va genera o cate o linie din matrice, cu numere aleatoare.
Predicatul se va opri cand numarul de linii ajunge sa fie 0 (moment in care seteaza coda matricii la lista vida (ca sa se adune in fata ei toate liniile generate in pasii din apelurile recursive anterioare):
matrice_random(0,_,_,_,[]).
Sa definim acum si linie_random(+NC,+A,+B, -Linie). Variabila NC reprezinta numarul de coloane, deci numarul de elemente de pe o linie. Folosim strategia de mai sus, si decrementam NC cu 1, dupa generarea fiecarui element din linie. Ne vom opri cand NC ajunge 0, moment in care finalizam linia cu o lista vida (acesta fiind ultimul tail al listei, in fata caruia se vor aduna toate elementele generate in apelurile recursive anterioare).
linie_random(N, A,B,[H|T]):- N>0, N1 is N-1, random(A,B,H), linie_random(N1,A,B,T).
linie_random(0, _,_,[]).
Avand in vedere cele explicate mai sus, iata si programul complet:
:-use_module(library(random)).
:-use_module(library(system)).
:-seteaza_seed.
seteaza_seed:-now(X1), X is X1 mod 30000,
now(B),setrand(random(X,100,100,B)).
genereaza_matrice_random(N,A,B,M):- matrice_random(N,N,A,B,M).
%matrice_random(+NrLinii,+NrColoane,+A,+B,-M)
matrice_random(NL,NC, A,B,[Linie|M]):- NL>0, linie_random(NC,A,B, Linie), NL1 is NL-1, matrice_random(NL1,NC,A,B,M).
matrice_random(0,_,_,_,[]).
%linie_random(+NrColoane,+A,+B, -Linie)
linie_random(N, A,B,[H|T]):- N>0, N1 is N-1, random(A,B,H), linie_random(N1,A,B,T).
linie_random(0, _,_,[]).
Un exemplu de executie ar fi:
| ?- genereaza_matrice_random(7,1,11,M).
M = [[1,10,8,6,2,8,8],[6,1,1,5,2,4,2],[5,6,9,6,9,5,7],[9,2,6,8,5,2,5],[7,5,9,8,4,7|...],[2,10,2,3,6|...],[5,5,9,5|...]] ? <100
M = [[1,10,8,6,2,8,8],[6,1,1,5,2,4,2],[5,6,9,6,9,5,7],[9,2,6,8,5,2,5],[7,5,9,8,4,7,7],[2,10,2,3,6,8,2],[5,5,9,5,2,6,10]] ?
yes
| ?-
Observati ca prima oara cand a oferit solutia, unele liste erau date incomplet (cu "..."), motiv pentru care am marit bufferul cu comanda "<100".
Matricea obtinuta este:
1 10 8 6 2 8 8
6 1 1 5 2 4 2
5 6 9 6 9 5 7
9 2 6 8 5 2 5
7 5 9 8 4 7 7
2 10 2 3 6 8 2
5 5 9 5 2 6 10
Pozitii aleatoare in lista
Enuntul exercitiului. Sa se scrie un predicat care sterge intr-o ordine random numerele impare dintr-o lista de numere naturale. Dupa fiecare stergere va afisa lista rezultata. Forma predicatului va fi sterge_rand_impare(+L).
Pentru a putea sterge usor numerele trebuie sa stim cate sunt (notam cu Ni numarul de elemente impare). Astfel vom avea un predicat care numara cate elemente impare sunt in lista:
%numara_impare(+L,-Ni)
numara_impare([H|T],Ni):- numara_impare(T,NiT), (H mod 2 =:=0 -> Ni=NiT; Ni is NiT +1).
numara_impare([],0).
Avand numarul de numere impare Ni, la fiecare iteratie alegem un numar aleator K intre 0 si Ni (exclusiv):
random(0,Ni,K)
Apoi stergem al K-lea numar impar, dupa care afisam lista. Deci trebuie sa facem un predicat care stie sa stearga un element de pe o pozitie data:
%sterge_lista_poz(+Lista, +Pozitie, -ListaRezultata).
Pe care il vom apela:
sterge_lista_poz([_|T], 0, T).
sterge_lista_poz([H|T], Poz, [H|Trez]):- Poz>0, Poz1 is Poz-1, sterge_lista_poz(T,Poz1,Trez).
sterge_lista_poz(L,K,Lnou)
ca sa stergem elementul de pe pozitia random K.
De fiecare data cand stergem un numar, decrementam Ni deoarece scade numarul de elemente impare (de sters). Deci in predicatul care sterge elementele, va trebui sa avem si instructiunea:
NiNou is Ni-1
Astfel predicatul care sterge numerele impare va avea forma finala:
sterge_impare(L,Ni):- Ni>0, random(0,Ni,K), sterge_lista_poz(L,K,Lnou),write(Lnou),nl, NiNou is Ni-1, sterge_impare(Lnou, NiNou).
sterge_impare(_,0).
Avand in vedere cele explicate mai sus, iata si programul complet:
:-use_module(library(random)).
:-use_module(library(system)).
:-seteaza_seed.
seteaza_seed:-now(X1), X is X1 mod 30000,
now(B),setrand(random(X,100,100,B)).
%sterge_rand_impare(+L)
sterge_rand_impare(L):- numara_impare(L,Ni), sterge_impare(L,Ni).
%numara_impare(+L,-Ni)
numara_impare([H|T],Ni):- numara_impare(T,NiT), (H mod 2 =:=0 -> Ni=NiT; Ni is NiT +1).
numara_impare([],0).
sterge_impare(L,Ni):- Ni>0, random(0,Ni,K), sterge_lista_poz(L,K,Lnou),write(Lnou),nl, NiNou is Ni-1, sterge_impare(Lnou, NiNou).
sterge_impare(_,0).
%sterge_lista_poz(+Lista, +Pozitie, -ListaRezultata).
sterge_lista_poz([_|T], 0, T).
sterge_lista_poz([H|T], Poz, [H|Trez]):- Poz>0, Poz1 is Poz-1, sterge_lista_poz(T,Poz1,Trez).
Vom da doua exemple de executie pentru a se observa ordinea aleatoare a disparitiei elementelor:
| ?- sterge_rand_impare([1,4,5,8,7,9,11,10]).
[1,4,8,7,9,11,10]
[1,4,8,9,11,10]
[1,4,9,11,10]
[4,9,11,10]
[9,11,10]
yes
| ?- sterge_rand_impare([1,4,5,8,7,9,11,10]).
[1,5,8,7,9,11,10]
[5,8,7,9,11,10]
[5,8,9,11,10]
[8,9,11,10]
[9,11,10]
yes
| ?-
Functii de timp (din biblioteca system)
In exemple pot sa apara si predicate din alte biblioteci.
Enuntul exercitiului. Sa se scrie un predicat care citeste numere de la tastatura pana este intalnit numarul 0. Predicatul calculeaza suma numerelor in variabila S si, la final, afiseaza timpul executiei (in secunde).
In cazul in care se citeste altceva decat un numar, predicatul esueaza.
Pentru a calcula timpul de executie in secunde, ar trebui ca atat la inceputul predicatului cat si la sfarsitul predicatului sa preluam timestamp-urile, si apoi sa le scadem:
Masurarea timpului de executie
... now(TimpInitial), /* taskurile predicatului */ now(TimpFinal), Secunde is TimpFinal-TimpInitial ...
La inceputul programului vom sterge toate eventualele fapte ale predicatului suma (ne asiguram ca nu au ramas din vreo rulare anterioara) si adaugam un unic fapt cu suma egala cu 0:
retractall(suma(_)), assert(suma(0))
Repetitiv citim cate un X si daca acesta este numar si e diferit de zero, il vom aduna la suma memorata in predicatul dinamic. Astfel, vom prelua si sterge suma veche, vom aduna numarul la ea, obtinand suma noua si vom adauga suma noua in baza de cunostinte:
retract(suma(Sv)), Sn is Sv+X, assert(suma(Sn)),
Conditia de iesire din zona repetitiva va fi ca X==0.
Avand in vedere cele explicate mai sus, iata si programul complet:
:-use_module(library(system)).
:-dynamic suma/1.
citeste_numere(Suma):- now(TimpInitial),once((retractall(suma(_)), assert(suma(0)))),
repeat,
read(X),
(
X==0
;
number(X)->
retract(suma(Sv)), Sn is Sv+X, assert(suma(Sn)),fail
;
!, fail
),
!,
retract(suma(Suma)),
now(TimpFinal),
Secunde is TimpFinal-TimpInitial,
format('Secunde trecute: ~p\n', [Secunde]).
Doua exemple de executie ar fi:
| ?- citeste_numere(Suma).
|: 2.
|: 5.
|: 3.
|: 7.
|: 0.
Secunde trecute: 8
Suma = 17 ? yes
| ?-
| ?- citeste_numere(Suma).
|: 3.
|: a.
no
| ?-
Crearea unei "animatii" prin introducerea unui delay intre afisari
Enuntul exercitiului. Sa se scrie un predicat genereaza_animatie(+N) care primeste un numar N si genereaza o matrice de dimensiune N*N formata doar din zerouri. La fiecare jumatate de secunda un zero aleator din matrice se va transforma in simbolul *. Dupa fiecare astfel de schimbare, matricea va fi reafisata in locul matricei vechi (deci trebuie curatat ecranul inainte de reafisare). Timpul intre afisari este de jumatate de secunda. Predicatul se va termina cand in matrice nu se mai gasesc zerouri.
De exemplu, pentru N=5 vrem sa ajungem de la:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
la
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
Pentru generarea matricii initiale ne trebuie un predicat care primeste un numar N si un element Elem si genereaza o lista de lungime N cu toate elementele egale cu Elem:
list_identic(Elem, N, [Elem|T]):- N>0, N1 is N-1, list_identic(Elem, N1, T).
list_identic(_,0,[]).
Acest predicat il vom apela de doua ori. Prima oara ca sa cream o lista (linie in matrice) de lungime N formata doar din zerouri:
list_identic(0,N,Linie)
si a doua oara ca sa repetam de N ori linia creata, in matrice:
list_identic(Linie, N, M)
Strategia abordata va fi crearea unui contor cu numarul total de zerouri (care la inceput este chiar N*N):
Nr0 is N*N
si la fiecare inlocuire a unui zero cu asterisc, numarul va fi decrementat.
Inlocuirile se vor realiza pana Nr0 ajunge egal cu 0. La fiecare pas se genereaza un numar natural aleator (notat cu Poz) in intervalul [0, Nr0) si se parcurg elementele din matrice pana sa ajunge la al Poz-lea element 0 din matrice, moment in care acesta se inlocuieste.
Este necesar pentru a realiza animatia sa avem si un predicat de stergere a ecranului:
clear:-format('~c~s~c~s', [0x1b, "[H", 0x1b, "[2J"]).
De asemenea avem nevoie de un predicat de afisare a unei matrici, linie cu linie:
afis_mat([Linie|RestMatrice]):-afis_lin(Linie),afis_mat(RestMatrice).
afis_mat([]).
afis_lin([H]):-write(H),nl,!.
afis_lin([H|T]):-write(H),write(' '),afis_lin(T).
Avand in vedere cele explicate mai sus, iata si programul complet. Predicatul principal este genereaza_animatie.
:-use_module(library(random)).
:-use_module(library(system)).
:-seteaza_seed.
seteaza_seed:-now(X1), X is X1 mod 30000,
now(B),setrand(random(X,100,100,B)).
clear:-format('~c~s~c~s', [0x1b, "[H", 0x1b, "[2J"]).
list_identic(Elem, N, [Elem|T]):- N>0, N1 is N-1, list_identic(Elem, N1, T).
list_identic(_,0,[]).
genereaza_animatie(N):- list_identic(0,N,Linie), list_identic(Linie, N, M), Nr0 is N*N, animatie(M, Nr0).
animatie(M,Nr0):-Nr0>0, clear, random(0,Nr0,Poz),nl,schimba_poz_mat(Poz,M,Mnou), afis_mat(Mnou),nl,nl, sleep(0.5), Nr0_nou is Nr0-1, animatie(Mnou, Nr0_nou).
animatie(_,0).
afis_mat([Linie|RestMatrice]):-afis_lin(Linie),afis_mat(RestMatrice).
afis_mat([]).
afis_lin([H]):-write(H),nl,!.
afis_lin([H|T]):-write(H),write(' '),afis_lin(T).
schimba_poz_mat(Poz,[Linie|M],[LinieRez|MRez]):- Poz>=0, schimba_poz_in_linie(Poz, Linie, LinieRez, Poz1), schimba_poz_mat(Poz1, M, MRez).
schimba_poz_mat(-1,M,MRez):- MRez=M.
schimba_poz_in_linie(-1, Linie, LinieRez, -1) :- !, LinieRez=Linie.
schimba_poz_in_linie(Poz,[H|Linie], [HRez |LinieRez], Pozfinal):-
(H==0 ->
(Poz>0 ->
Poz1 is Poz-1,
HRez=H
;
Poz==0,
HRez='*',
Poz1 = -1
)
;
HRez=H, Poz1 is Poz
),
schimba_poz_in_linie(Poz1, Linie,LinieRez, Pozfinal).
schimba_poz_in_linie(Poz,[],[],Pozfinal):- Pozfinal=Poz.
Interogati voi predicatul pentru a vedea animatia.
Sistemul de fisiere
In exemple pot sa apara si predicate din alte biblioteci.
Enuntul exercitiului. Sa se scrie un predicat care primeste calea unei director si calculeaza intr-un parametru Nr cate fisiere contin in nume o litera data ( o vom nota cu Lit). Forma predicatului va fi cate_fisiere(+Director, +Litera, -Nr).
Mai intai obtinem lista de fisiere din director cu predicatul files_members_of_directory. Elementele din lista sunt de forma CaleRelativa-CaleAbsoluta. Vom parcurge lista element de element folosind doar calea relativa. La fiecare pas, transformam calea relativa in lista de caractere, eliminam extensia si apoi vedem daca litera data e membru in lista de caractere provenita din numele fisierului. Avand in vedere cele explicate mai sus, iata si programul complet:
Un exemplu de executie pentru folderul:Iterarea prin fisierele unui director
:-use_module(library(file_systems)).
cate_fisiere(Director, Litera, Nr):- file_members_of_directory(Director, LF), numara_fisiere(LF, Litera, Nr).
numara_fisiere([CR - _|T], Litera, Nr):- numara_fisiere(T, Litera, NrT), atom_chars(CR,LCR), append(Lnume,['.'|_], LCR), (member(Litera,Lnume)-> Nr is NrT+1; Nr is NrT).
numara_fisiere([],0).
ar fi:
| ?- cate_fisiere('D:/folder_test',a,Nr).
Nr = 3 ?
yes
| ?-