Diferencia entre revisiones de «Práctica 5 (pre 2010, Paradigmas)»

De Cuba-Wiki
Sin resumen de edición
Sin resumen de edición
Línea 10: Línea 10:
%padre(-Padre, -Hijo)  
%padre(-Padre, -Hijo)  
%esposo(-Hombre, -Mujer)  
%esposo(-Hombre, -Mujer)  
padre(john, sue).  
 
padre(john, bill).  
padre(john, sue).  
padre(bob, nancy).  
padre(john, bill).  
padre(bob, jeff).  
padre(bob, nancy).  
padre(bill, ron).  
padre(bob, jeff).  
esposo(john, mary).  
padre(bill, ron).  
esposo(bob, sue).  
esposo(john, mary).  
esposo(bill, jane).  
esposo(bob, sue).  
hombre(john).  
esposo(bill, jane).  
hombre(bob).  
hombre(john).  
hombre(jeff).  
hombre(bob).  
hombre(bill).  
hombre(jeff).  
hombre(ron).  
hombre(bill).  
mujer(mary).  
hombre(ron).  
mujer(sue).  
mujer(mary).  
mujer(nancy).  
mujer(sue).  
mujer(jane).  
mujer(nancy).  
mujer(jane).  


%hijo( -Hijo, -Persona)  
%hijo( -Hijo, -Persona)  
hijo(Hijo, Persona) :- hombre(Persona), padre(Persona, Hijo).  
hijo(Hijo, Persona) :- hombre(Persona), padre(Persona, Hijo).  
hijo(Hijo, Persona) :- mujer(Persona), esposo(Esposo, Persona), hijo(Hijo, Esposo).  
hijo(Hijo, Persona) :- mujer(Persona), esposo(Esposo, Persona), hijo(Hijo, Esposo).  


%abuelo(-Abuelo, -Nieto)  
%abuelo(-Abuelo, -Nieto)  
abuelo(Abuelo, Nieto) :- hijo(Nieto, Progenitor), hijo(Progenitor, Abuelo).  
abuelo(Abuelo, Nieto) :- hijo(Nieto, Progenitor), hijo(Progenitor, Abuelo).  


%progenitor(-Progenitor, -Hijo)  
%progenitor(-Progenitor, -Hijo)  
progenitor(Progenitor, Hijo) :- hijo(Hijo, Progenitor).  
progenitor(Progenitor, Hijo) :- hijo(Hijo, Progenitor).  


%hermano(-Hermano, -Persona)  
%hermano(-Hermano, -Persona)  
hermano(Hermano, Persona) :- progenitor(Progenitor, Hermano), progenitor(Progenitor, Persona), Hermano \= Persona.  
hermano(Hermano, Persona) :- progenitor(Progenitor, Hermano), progenitor(Progenitor, Persona), Hermano \= Persona.  


%descendiente(-Descendiente, -Ascendiente)  
%descendiente(-Descendiente, -Ascendiente)  
descendiente(Descendiente, Ascendiente) :- hijo(Descendiente, Ascendiente).  
descendiente(Descendiente, Ascendiente) :- hijo(Descendiente, Ascendiente).  
descendiente(Descendiente, Ascendiente) :- hijo(Descendiente, Padre), descendiente(Padre, Ascendiente).  
descendiente(Descendiente, Ascendiente) :- hijo(Descendiente, Padre), descendiente(Padre, Ascendiente).  


%tio(-Tio, -Sobrino)  
%tio(-Tio, -Sobrino)  
tio(Tio, Sobrino) :- hijo(Sobrino, Padre), hermano(Tio, Padre).  
tio(Tio, Sobrino) :- hijo(Sobrino, Padre), hermano(Tio, Padre).  


% ii. Defina una nueva relaci´on primo. ¿C´omo se puede definir una consulta para conocer todos los  
% ii. Defina una nueva relaci´on primo. ¿C´omo se puede definir una consulta para conocer todos los  
Línea 52: Línea 53:


%primo(-Primo, -OtroPrimo)  
%primo(-Primo, -OtroPrimo)  
primo(Primo, OtroPrimo) :- abuelo(Abuelo, Primo), abuelo(Abuelo, OtroPrimo), Primo \= OtroPrimo.  
primo(Primo, OtroPrimo) :- abuelo(Abuelo, Primo), abuelo(Abuelo, OtroPrimo), Primo \= OtroPrimo.  


%ii. Respuesta: primo(ron, Primo).  
%ii. Respuesta: primo(ron, Primo).  
Línea 72: Línea 73:


% iii. c. ancestro:  
% iii. c. ancestro:  
ancestro(X, X).  
ancestro(X, X).  
ancestro(X, Y) :- ancestro(Z, Y), progenitor(X, Z).  
ancestro(X, Y) :- ancestro(Z, Y), progenitor(X, Z).  




Línea 83: Línea 84:


%nn(-X).  
%nn(-X).  
nn(cero).  
nn(cero).  
nn(sucesor(X)) :- nn(X).  
nn(sucesor(X)) :- nn(X).  


tonn(0, cero).  
tonn(0, cero).  
tonn(X, sucesor(Y)) :- X > 0, PrevX is X - 1, tonn(PrevX, Y).  
tonn(X, sucesor(Y)) :- X > 0, PrevX is X - 1, tonn(PrevX, Y).  


% i. moi(-X, +Y) sii X es menor o igual que Y.  
% i. moi(-X, +Y) sii X es menor o igual que Y.  
moi(cero, Y) :- nn(Y).  
moi(cero, Y) :- nn(Y).  
moi(sucesor(X), sucesor(Y)) :- moi(X, Y).  
moi(sucesor(X), sucesor(Y)) :- moi(X, Y).  


% menor(-X, +Y) sii X es menor que Y.  
% menor(-X, +Y) sii X es menor que Y.  
menor(cero, sucesor(Y)) :- nn(Y).  
menor(cero, sucesor(Y)) :- nn(Y).  
menor(sucesor(X), sucesor(Y)) :- menor(X, Y).  
menor(sucesor(X), sucesor(Y)) :- menor(X, Y).  


% ii. producto(+X, +Y, -Z) sii Z es el producto de X con Y.  
% ii. producto(+X, +Y, -Z) sii Z es el producto de X con Y.  
%suma(-X, -Y, -Z) sii Z es la suma de X con Y.  
%suma(-X, -Y, -Z) sii Z es la suma de X con Y.  
suma(X, cero, X) :- nn(X).  
suma(X, cero, X) :- nn(X).  
suma(X, sucesor(Y), sucesor(Z)) :- suma(X, Y, Z).  
suma(X, sucesor(Y), sucesor(Z)) :- suma(X, Y, Z).  


%producto(+X, +Y, -Z)  
%producto(+X, +Y, -Z)  
producto(X, cero, cero) :- nn(X).  
producto(X, cero, cero) :- nn(X).  
producto(X, sucesor(Y), Z) :- producto(X, Y, XPorY), suma(X, XPorY, Z).  
producto(X, sucesor(Y), Z) :- producto(X, Y, XPorY), suma(X, XPorY, Z).  


% iii. fact(+X, -F) sii F es el factorial de X.  
% iii. fact(+X, -F) sii F es el factorial de X.  
%iii. fact(+X, -F) sii F es el factorial de X.  
%iii. fact(+X, -F) sii F es el factorial de X.  
fact(cero, sucesor(cero)).  
fact(cero, sucesor(cero)).  
fact(sucesor(X), F) :- fact(X, PrevF), producto(sucesor(X), PrevF, F).  
fact(sucesor(X), F) :- fact(X, PrevF), producto(sucesor(X), PrevF, F).  


%iv. mod(+X, +Y, -Z) sii Z es el resto de la divisi´on entrera entre X e Y. Definicion recursiva.  
%iv. mod(+X, +Y, -Z) sii Z es el resto de la divisi´on entrera entre X e Y. Definicion recursiva.  
mod(X, X, cero) :- X \= cero, nn(X).  
mod(X, X, cero) :- X \= cero, nn(X).  
mod(X, Y, X) :- Y \= cero, X \= Y, moi(X, Y).  
mod(X, Y, X) :- Y \= cero, X \= Y, moi(X, Y).  
mod(X, Y, Z) :- Y \= cero, suma(XMenosY, Y, X), mod(XMenosY, Y, Z).  
mod(X, Y, Z) :- Y \= cero, suma(XMenosY, Y, X), mod(XMenosY, Y, Z).  


%iv. modNR(+X, +Y, -Z) sii Z es el resto de la divisi´on entrera entre X e Y. Definicion no recursiva.  
%iv. modNR(+X, +Y, -Z) sii Z es el resto de la divisi´on entrera entre X e Y. Definicion no recursiva.  
%Propiedad: Z + K * Y = X  
%Propiedad: Z + K * Y = X  
modNR(X, X, cero) :- X \= cero, nn(X).  
modNR(X, X, cero) :- X \= cero, nn(X).  
modNR(X, Y, X) :- Y \= cero, X \= Y, moi(X, Y).  
modNR(X, Y, X) :- Y \= cero, X \= Y, moi(X, Y).  
modNR(X, Y, Z) :- Y \= cero, moi(K, X), menor(Z, Y), producto(K, Y, CasiX), suma(CasiX, Z, X).  
modNR(X, Y, Z) :- Y \= cero, moi(K, X), menor(Z, Y), producto(K, Y, CasiX), suma(CasiX, Z, X).  


%v. Definir un predicado unario que determine si un n´umero entero dado es primo. Tener en cuenta que el argumento siempre est´a instanciado.  
%v. Definir un predicado unario que determine si un n´umero entero dado es primo. Tener en cuenta que el argumento siempre est´a instanciado.  
no_es_primo(cero).  
no_es_primo(cero).  
no_es_primo(sucesor(cero)).  
no_es_primo(sucesor(cero)).  
no_es_primo(X) :- nn(X), menor(Menor, X), menor(sucesor(cero), Menor), mod(X, Menor, cero).  
no_es_primo(X) :- nn(X), menor(Menor, X), menor(sucesor(cero), Menor), mod(X, Menor, cero).  
primo(X) :- not(no_es_primo(X)).  
primo(X) :- not(no_es_primo(X)).  




sumaPrimo(float(Entera1, Dec1), float(Entera2, Dec2)) :-  
sumaPrimo(float(Entera1, Dec1), float(Entera2, Dec2)) :-  
sumaPrimo(float(Entera1, Dec1), float(Entera2, Dec2)) :- noventaYNueve(N99), moi(Dec1, N99), moi(Dec2, N99),  
sumaPrimo(float(Entera1, Dec1), float(Entera2, Dec2)) :- noventaYNueve(N99), moi(Dec1, N99), moi(Dec2, N99),  
producto(Entera1, suc(N99), Ent1), producto(Entera2, suc(N99), Ent2),  
producto(Entera1, suc(N99), Ent1), producto(Entera2, suc(N99), Ent2),  
suma(Ent1, Dec1, Num1), suma(Ent2, Dec2, Num2), moi(Num1, Num2),  
suma(Ent1, Dec1, Num1), suma(Ent2, Dec2, Num2), moi(Num1, Num2),  
suma(Entera2, Dec2, Primo), primo(Primo).  
suma(Entera2, Dec2, Primo), primo(Primo).  


==Ejercicio 03==
==Ejercicio 03==
Línea 145: Línea 146:
% append( [H | T], Y, [H | Z]) :- append(T, Y, Z).  
% append( [H | T], Y, [H | Z]) :- append(T, Y, Z).  


last(L, U) :- append(_, [U], L).  
last(L, U) :- append(_, [U], L).  


% ii. reverse(+L, -L1), donde L1 contiene los mismos elementos que L, pero en orden inverso.  
% ii. reverse(+L, -L1), donde L1 contiene los mismos elementos que L, pero en orden inverso.  
Línea 156: Línea 157:
% reverse: como se hace reverse sin append?  
% reverse: como se hace reverse sin append?  


reverse2([], []).  
reverse2([], []).  
reverse2([H | T], R) :- reverse2(T, ReversedT), append(ReversedT, [H], R).  
reverse2([H | T], R) :- reverse2(T, ReversedT), append(ReversedT, [H], R).  


% iii. maxlista(+L, -M) y minlista(+L, -M), donde M es el m´aximo/m´inimo de la lista L.  
% iii. maxlista(+L, -M) y minlista(+L, -M), donde M es el m´aximo/m´inimo de la lista L.  
maxlista([H], H).  
maxlista([H], H).  
maxlista([H | T], H) :- maxlista(T, M), H >= M.  
maxlista([H | T], H) :- maxlista(T, M), H >= M.  
maxlista([H | T], M) :- maxlista(T, M), H < M.  
maxlista([H | T], M) :- maxlista(T, M), H < M.  


minlista([H], H).  
minlista([H], H).  
minlista([H | T], H) :- minlista(T, M), H =< M.  
minlista([H | T], H) :- minlista(T, M), H =< M.  
minlista([H | T], M) :- minlista(T, M), H > M.  
minlista([H | T], M) :- minlista(T, M), H > M.  


% iv. palindromo(+L, -L1), donde L1 es un pal´indromo construido a partir de L.  
% iv. palindromo(+L, -L1), donde L1 es un pal´indromo construido a partir de L.  
% Ejemplo: palindromo([a,b,c], [a,b,c,c,b,a]).  
% Ejemplo: palindromo([a,b,c], [a,b,c,c,b,a]).  
palindromo(L, P) :- reverse2(L, RevL), append(L, RevL, P).  
palindromo(L, P) :- reverse2(L, RevL), append(L, RevL, P).  


% v. doble(-L, -L1), donde cada elemento de L aparece dos veces en L1.  
% v. doble(-L, -L1), donde cada elemento de L aparece dos veces en L1.  
% Ejemplo: doble([a,b,c], [a,a,b,b,c,c]).  
% Ejemplo: doble([a,b,c], [a,a,b,b,c,c]).  
doble([], []).  
doble([], []).  
doble([H | T], [H | H | DT]) :- doble(T, DT).  
doble([H | T], [H | H | DT]) :- doble(T, DT).  


% vi. prefijo(-P, +L), donde P es prefijo de la lista L.  
% vi. prefijo(-P, +L), donde P es prefijo de la lista L.  
prefijo(P, L) :- append(P, _, L).  
prefijo(P, L) :- append(P, _, L).  


% vii. sufijo(-S, +L), donde S es sufijo de la lista L.  
% vii. sufijo(-S, +L), donde S es sufijo de la lista L.  
sufijo(P, L) :- append(_, P, L).  
sufijo(P, L) :- append(_, P, L).  


% viii. sublista(-S, +L), donde S es sublista de L.  
% viii. sublista(-S, +L), donde S es sublista de L.  
% Esta version es para sublistas "continuas" en L.  
% Esta version es para sublistas "continuas" en L.  
sublista([], _).  
sublista([], _).  
sublista(S, L) :- append(CasiL, _, L), append(_, S, CasiL), S \= [].  
sublista(S, L) :- append(CasiL, _, L), append(_, S, CasiL), S \= [].  


% Esta version es para sublistas "no continuas" en L.  
% Esta version es para sublistas "no continuas" en L.  


sublistaB([], []).  
sublistaB([], []).  
sublistaB([H | SubsT], [H | T]) :- sublistaB(SubsT, T).  
sublistaB([H | SubsT], [H | T]) :- sublistaB(SubsT, T).  
sublistaB(SubsT, [_ | T]) :- sublistaB(SubsT, T).  
sublistaB(SubsT, [_ | T]) :- sublistaB(SubsT, T).  


% ix. iesimo(-I, +L, -X), donde X es el I-´esimo elemento de la lista L.  
% ix. iesimo(-I, +L, -X), donde X es el I-´esimo elemento de la lista L.  
% Ejemplo: iesimo(2, [10, 20, 30, 40], 20).  
% Ejemplo: iesimo(2, [10, 20, 30, 40], 20).  
iesimo(I, L, X) :- append(ListI, [X | _], L), length(ListI, I).  
iesimo(I, L, X) :- append(ListI, [X | _], L), length(ListI, I).  


% Definir los siguientes predicados:  
% Definir los siguientes predicados:  
Línea 204: Línea 205:
% viceversa.  
% viceversa.  
% Ejemplo: mezcla([a,b,c], [d,e], [a,d,b,e,c]).  
% Ejemplo: mezcla([a,b,c], [d,e], [a,d,b,e,c]).  
mezcla(L1, [], L1).  
mezcla(L1, [], L1).  
mezcla([], L2, L2).  
mezcla([], L2, L2).  
mezcla([H1 | T1], [H2 | T2], [H1, H2 | T12]) :- mezcla(T1, T2, T12).  
mezcla([H1 | T1], [H2 | T2], [H1, H2 | T12]) :- mezcla(T1, T2, T12).  


% ii. split(N, L, L1, L2), donde L1 tiene los N primeros elementos de L, y L2 el resto. Si L tiene  
% ii. split(N, L, L1, L2), donde L1 tiene los N primeros elementos de L, y L2 el resto. Si L tiene  
% menos de N elementos el predicado debe fallar. ¿Cu´an reversible es este predicado? Es decir,  
% menos de N elementos el predicado debe fallar. ¿Cu´an reversible es este predicado? Es decir,  
% ¿qu´e elementos pueden estar indefinidos al momento de la invocaci´on?  
% ¿qu´e elementos pueden estar indefinidos al momento de la invocaci´on?  
split(N, L, L1, L2) :- append(L1, L2, L), length(L1, N).  
split(N, L, L1, L2) :- append(L1, L2, L), length(L1, N).  


% iii. borrar(+ListaConXs, +X, -ListaSinXs), que elimina todas las ocurrencias de X de la lista  
% iii. borrar(+ListaConXs, +X, -ListaSinXs), que elimina todas las ocurrencias de X de la lista  
% ListaConXs.  
% ListaConXs.  
borrar([], _, []).  
borrar([], _, []).  
borrar([H | XS], E, [H | YS]) :- E \= H, borrar(XS, E, YS).  
borrar([H | XS], E, [H | YS]) :- E \= H, borrar(XS, E, YS).  
borrar([E | XS], E, YS) :- borrar(XS, E, YS).  
borrar([E | XS], E, YS) :- borrar(XS, E, YS).  


% iv. sacarDuplicados(+L1, -L2), que saca todos los elementos duplicados de la lista L1.  
% iv. sacarDuplicados(+L1, -L2), que saca todos los elementos duplicados de la lista L1.  
pertenece(E, L1) :- append(Principio, _, L1), append(_, [E], Principio).  
pertenece(E, L1) :- append(Principio, _, L1), append(_, [E], Principio).  
sacarDuplicados([], []).  
sacarDuplicados([], []).  
sacarDuplicados([H | T], [H | SinDups]) :- borrar(T, H, BorrarH), sacarDuplicados(BorrarH, SinDups).  
sacarDuplicados([H | T], [H | SinDups]) :- borrar(T, H, BorrarH), sacarDuplicados(BorrarH, SinDups).  
sacarDuplicados([H | T], SinDups) :- pertenece(H, T), sacarDuplicados(T, SinDups).  
sacarDuplicados([H | T], SinDups) :- pertenece(H, T), sacarDuplicados(T, SinDups).  


%Ejecicio 7  
%Ejecicio 7  
Línea 233: Línea 234:
%?- aplanar([a, [3, b, []], [2]], [a, 3, b, 2]).  
%?- aplanar([a, [3, b, []], [2]], [a, 3, b, 2]).  
%?- aplanar([[1, [2, 3], [a]], [[[]]]], [1, 2, 3, a]).  
%?- aplanar([[1, [2, 3], [a]], [[[]]]], [1, 2, 3, a]).  
aplanar([], []).  
aplanar([], []).  
aplanar([H | T], App) :- is_list(H), aplanar(H, AppH), aplanar(T, AppT), append(AppH, AppT, App).  
aplanar([H | T], App) :- is_list(H), aplanar(H, AppH), aplanar(T, AppT), append(AppH, AppT, App).  
aplanar([H | T], App) :- not(is_list(H)), aplanar(T, AppT), append([H], AppT, App).  
aplanar([H | T], App) :- not(is_list(H)), aplanar(T, AppT), append([H], AppT, App).  


==Ejercicio 08==
==Ejercicio 08==
%Definir los siguientes predicados:  
%Definir los siguientes predicados:  
%i. ordenada(+L), que ser´a cierta si los elementos de L est´an ordenados en forma ascendente.  
%i. ordenada(+L), que ser´a cierta si los elementos de L est´an ordenados en forma ascendente.  
ordenada([]).  
ordenada([]).  
ordenada([_]).  
ordenada([_]).  
ordenada([X, Y | XS]) :- X =< Y, ordenada([Y | XS]).  
ordenada([X, Y | XS]) :- X =< Y, ordenada([Y | XS]).  


%ii. quicksort(+L, -L1), donde L1 es el resultado de ordenar L por el m´etodo de quicksort, que  
%ii. quicksort(+L, -L1), donde L1 es el resultado de ordenar L por el m´etodo de quicksort, que  
%consiste en dividir a L en 2 sublistas con los menores y mayores al primer elemento, ordenar cada  
%consiste en dividir a L en 2 sublistas con los menores y mayores al primer elemento, ordenar cada  
%una de ellas y luego proceder a concatenarlas.  
%una de ellas y luego proceder a concatenarlas.  
quicksort_partir([], _, [], []).  
quicksort_partir([], _, [], []).  
quicksort_partir([H | T], E, [H | Menores], Mayores) :- (H =< E), quicksort_partir(T, E, Menores, Mayores).  
quicksort_partir([H | T], E, [H | Menores], Mayores) :- (H =< E), quicksort_partir(T, E, Menores, Mayores).  
quicksort_partir([H | T], E, Menores, [H | Mayores]) :- H > E, quicksort_partir(T, E, Menores, Mayores).  
quicksort_partir([H | T], E, Menores, [H | Mayores]) :- H > E, quicksort_partir(T, E, Menores, Mayores).  


quicksort([], []).  
quicksort([], []).  
quicksort([H | T], S) :- quicksort_partir(T, H, Menores, Mayores), quicksort(Menores, MenOrd),  
quicksort([H | T], S) :- quicksort_partir(T, H, Menores, Mayores), quicksort(Menores, MenOrd),  
quicksort(Mayores, MayOrd), append(MenOrd, [H | MayOrd], S).  
quicksort(Mayores, MayOrd), append(MenOrd, [H | MayOrd], S).  


%iii. inssort(+L, -L1), donde L1 es el resultado de ordenar L por el m´etodo de inserci´on, que  
%iii. inssort(+L, -L1), donde L1 es el resultado de ordenar L por el m´etodo de inserci´on, que  
%consiste en insertar cada elemento en el lugar adecuado del resto de la lista ya ordenada.  
%consiste en insertar cada elemento en el lugar adecuado del resto de la lista ya ordenada.  
insertar_ordenado([], E, [E]).  
insertar_ordenado([], E, [E]).  
insertar_ordenado([H | T], E, [E, H | T]) :- E =< H.  
insertar_ordenado([H | T], E, [E, H | T]) :- E =< H.  
insertar_ordenado([H | T], E, [H | S]) :- E > H, insertar_ordenado(T, E, S).  
insertar_ordenado([H | T], E, [H | S]) :- E > H, insertar_ordenado(T, E, S).  


inssort([], []).  
inssort([], []).  
inssort([H | T], S) :- inssort(T, SortT), insertar_ordenado(SortT, H, S).  
inssort([H | T], S) :- inssort(T, SortT), insertar_ordenado(SortT, H, S).  


% Ejercicio 9  
% Ejercicio 9  
Línea 271: Línea 272:
% rotar([1, a, 2, b, 3], -3, X) debe dar como respuesta X = [b, 3, 1, a, 2]  
% rotar([1, a, 2, b, 3], -3, X) debe dar como respuesta X = [b, 3, 1, a, 2]  


modulus(N, Modulus, Result) :- Result is ((N mod Modulus) + Modulus) mod Modulus.  
modulus(N, Modulus, Result) :- Result is ((N mod Modulus) + Modulus) mod Modulus.  


rotar(L, N, R) :- length(L, Length), modulus(N, Length, Rotate), append(Init, Tail, L),  
rotar(L, N, R) :- length(L, Length), modulus(N, Length, Rotate), append(Init, Tail, L),  
length(Tail, Rotate), append(Tail, Init, R).  
length(Tail, Rotate), append(Tail, Init, R).  


==Ejercicio 10==
==Ejercicio 10==
Línea 281: Línea 282:
% respetando su orden de aparici´on. Considerar que la lista original siempre est´a instanciada.  
% respetando su orden de aparici´on. Considerar que la lista original siempre est´a instanciada.  
% Ejemplo: para la lista [2, 3, 1, 0, 2] la salida es [2, 2, 3, 3, 3, 1, 2, 2].  
% Ejemplo: para la lista [2, 3, 1, 0, 2] la salida es [2, 2, 3, 3, 3, 1, 2, 2].  
repetir_n(_, 0, []).  
repetir_n(_, 0, []).  
repetir_n(E, Times, [E | T]) :- Times > 0, TimesMenos1 is Times - 1, repetir_n(E, TimesMenos1, T).  
repetir_n(E, Times, [E | T]) :- Times > 0, TimesMenos1 is Times - 1, repetir_n(E, TimesMenos1, T).  


repetir_numeros([], []).  
repetir_numeros([], []).  
repetir_numeros([H | T], Reps) :- repetir_n(H, H, Hs), repetir_numeros(T, Ts), append(Hs, Ts, Reps).  
repetir_numeros([H | T], Reps) :- repetir_n(H, H, Hs), repetir_numeros(T, Ts), append(Hs, Ts, Reps).  


==Ejercicio 11==
==Ejercicio 11==
Línea 291: Línea 292:
% se halla en la posici´on del medio de dicha lista, tras ser ordenada). Utilizar los predicados definidos  
% se halla en la posici´on del medio de dicha lista, tras ser ordenada). Utilizar los predicados definidos  
% anteriormente. Considerar que la lista siempre est´a instanciada.  
% anteriormente. Considerar que la lista siempre est´a instanciada.  
mediana(L, M) :- quicksort(L, S), length(L, Length), Mitad is Length // 2,  
mediana(L, M) :- quicksort(L, S), length(L, Length), Mitad is Length // 2,  
append(Primeros, [M | _], S), length(Primeros, Mitad).  
append(Primeros, [M | _], S), length(Primeros, Mitad).  


==Ejercicio 12==
==Ejercicio 12==
Línea 299: Línea 300:
% interseccion(+X, +Y, -Z), tal que Z es la intersecci´on sin repeticiones de las listas X e Y,  
% interseccion(+X, +Y, -Z), tal que Z es la intersecci´on sin repeticiones de las listas X e Y,  
% % respetando en Z el orden en que aparecen los elementos en X.  
% % respetando en Z el orden en que aparecen los elementos en X.  
interseccion_con_duplicados([], _, []).  
interseccion_con_duplicados([], _, []).  
interseccion_con_duplicados([H | T], Y, [H | IntTY]) :- pertenece(H, Y), interseccion_con_duplicados(T, Y, IntTY).  
interseccion_con_duplicados([H | T], Y, [H | IntTY]) :- pertenece(H, Y), interseccion_con_duplicados(T, Y, IntTY).  
interseccion_con_duplicados([H | T], Y, IntTY) :- not(pertenece(H, Y)), interseccion_con_duplicados(T, Y, IntTY).  
interseccion_con_duplicados([H | T], Y, IntTY) :- not(pertenece(H, Y)), interseccion_con_duplicados(T, Y, IntTY).  


interseccion(X, Y, Z) :- interseccion_con_duplicados(X, Y, W), sacarDuplicados(W, Z).  
interseccion(X, Y, Z) :- interseccion_con_duplicados(X, Y, W), sacarDuplicados(W, Z).  




Línea 315: Línea 316:
% i. Definir predicados en Prolog para las operaciones comunes de ´arboles: vacio, raiz, altura y  
% i. Definir predicados en Prolog para las operaciones comunes de ´arboles: vacio, raiz, altura y  
% cantidadNodos. Asumir siempre que el ´arbol est´a instanciado.  
% cantidadNodos. Asumir siempre que el ´arbol est´a instanciado.  
max(X, Y, X) :- X >= Y.  
max(X, Y, X) :- X >= Y.  
max(X, Y, Y) :- X < Y.  
max(X, Y, Y) :- X < Y.  
min(X, Y, X) :- X < Y.  
min(X, Y, X) :- X < Y.  
min(X, Y, Y) :- X >= Y.  
min(X, Y, Y) :- X >= Y.  
 


%vacio(+Arbol).  
%vacio(+Arbol).  
vacio(nil).  
vacio(nil).  


%raiz(+Arbol, -Raiz).  
%raiz(+Arbol, -Raiz).  
raiz(bin(_, Raiz, _), Raiz).  
raiz(bin(_, Raiz, _), Raiz).  


%altura(+Arbol, -Altura).  
%altura(+Arbol, -Altura).  
altura(nil, 0).  
altura(nil, 0).  
altura(bin(Izq, _, Der), N) :- altura(Izq, AlturaI), altura(Der, AlturaD),  
altura(bin(Izq, _, Der), N) :- altura(Izq, AlturaI), altura(Der, AlturaD),  
max(AlturaI, AlturaD, N).  
max(AlturaI, AlturaD, N).  


%cantidadNodos(+Arbol, -Cantidad).  
%cantidadNodos(+Arbol, -Cantidad).  
cantidadNodos(nil, 0).  
cantidadNodos(nil, 0).  
cantidadNodos(bin(Izq, _, Der), N) :- cantidadNodos(Izq, CantI), cantidadNodos(Der, CantD),  
cantidadNodos(bin(Izq, _, Der), N) :- cantidadNodos(Izq, CantI), cantidadNodos(Der, CantD),  
N is CantI + CantD + 1.  
N is CantI + CantD + 1.  


% ii. Se define la profundidad de un nodo como la distancia desde la ra´iz hasta el mismo (la ra´iz  
% ii. Se define la profundidad de un nodo como la distancia desde la ra´iz hasta el mismo (la ra´iz  
Línea 348: Línea 348:


%hpp(+Arbol, -L)  
%hpp(+Arbol, -L)  
hpp_con_duplicados(nil, 0, []).  
hpp_con_duplicados(nil, 0, []).  
hpp_con_duplicados(nil, 1, []).  
hpp_con_duplicados(nil, 1, []).  
hpp_con_duplicados(bin(Izq, Root, Der), 0, [Root | Res]) :- hpp_con_duplicados(Izq, 1, ResI), hpp_con_duplicados(Der, 1, ResD),  
hpp_con_duplicados(bin(Izq, Root, Der), 0, [Root | Res]) :- hpp_con_duplicados(Izq, 1, ResI), hpp_con_duplicados(Der, 1, ResD),  
append(ResI, ResD, Res).  
append(ResI, ResD, Res).  
hpp_con_duplicados(bin(Izq, _, Der), 1, Res) :- hpp_con_duplicados(Izq, 0, ResI), hpp_con_duplicados(Der, 0, ResD),  
hpp_con_duplicados(bin(Izq, _, Der), 1, Res) :- hpp_con_duplicados(Izq, 0, ResI), hpp_con_duplicados(Der, 0, ResD),  
append(ResI, ResD, Res).  
append(ResI, ResD, Res).  


% iv. sacarDuplicados(+L1, -L2), que saca todos los elementos duplicados de la lista L1.  
% iv. sacarDuplicados(+L1, -L2), que saca todos los elementos duplicados de la lista L1.  
pertenece(E, L1) :- append(Principio, _, L1), append(_, [E], Principio).  
pertenece(E, L1) :- append(Principio, _, L1), append(_, [E], Principio).  
sacarDuplicados([], []).  
sacarDuplicados([], []).  
sacarDuplicados([H | T], [H | SinDups]) :- borrar(T, H, BorrarH), sacarDuplicados(BorrarH, SinDups).  
sacarDuplicados([H | T], [H | SinDups]) :- borrar(T, H, BorrarH), sacarDuplicados(BorrarH, SinDups).  
sacarDuplicados([H | T], SinDups) :- pertenece(H, T), sacarDuplicados(T, SinDups).  
sacarDuplicados([H | T], SinDups) :- pertenece(H, T), sacarDuplicados(T, SinDups).  


hpp(Arbol, Res) :- hpp_con_duplicados(Arbol, 0, Dups), append([_], L, Dups), sacarDuplicados(L, Res).  
hpp(Arbol, Res) :- hpp_con_duplicados(Arbol, 0, Dups), append([_], L, Dups), sacarDuplicados(L, Res).  




Línea 368: Línea 368:
% ejercicio 13:  
% ejercicio 13:  
% i. aBB(+T) que ser´a verdadero si T es un ´arbol binario de b´usqueda.  
% i. aBB(+T) que ser´a verdadero si T es un ´arbol binario de b´usqueda.  
maximo_vs(nil, N, N).  
maximo_vs(nil, N, N).  
maximo_vs(bin(Izq, Root, Der), N, Max) :- maximo_vs(Izq, Root, MaxI), maximo_vs(Der, N, MaxD),  
maximo_vs(bin(Izq, Root, Der), N, Max) :- maximo_vs(Izq, Root, MaxI), maximo_vs(Der, N, MaxD),  
max(MaxI, MaxD, Max).  
max(MaxI, MaxD, Max).  
minimo_vs(nil, N, N).  
minimo_vs(nil, N, N).  
minimo_vs(bin(Izq, Root, Der), N, Min) :- minimo_vs(Izq, Root, MinI), minimo_vs(Der, N, MinD),  
minimo_vs(bin(Izq, Root, Der), N, Min) :- minimo_vs(Izq, Root, MinI), minimo_vs(Der, N, MinD),  
min(MinI, MinD, Min).  
min(MinI, MinD, Min).  


aBB(nil).  
aBB(nil).  
aBB(bin(Izq, Root, Der)) :- aBB(Izq), aBB(Der), maximo_vs(Izq, Root, Root),  
aBB(bin(Izq, Root, Der)) :- aBB(Izq), aBB(Der), maximo_vs(Izq, Root, Root),  
minimo_vs(Der, Root + 1, Root + 1).  
minimo_vs(Der, Root + 1, Root + 1).  


% ii. aBBInsertar(+X, +T1, -T2) donde T2 resulta de insertar X en orden en el ´arbol T1.  
% ii. aBBInsertar(+X, +T1, -T2) donde T2 resulta de insertar X en orden en el ´arbol T1.  
aBBInsertar(X, nil, bin(nil, X, nil)).  
aBBInsertar(X, nil, bin(nil, X, nil)).  
aBBInsertar(X, bin(Izq, Root, Der), bin(NuevoIzq, Root, Der)) :- X =< Root, aBBInsertar(X, Izq, NuevoIzq).  
aBBInsertar(X, bin(Izq, Root, Der), bin(NuevoIzq, Root, Der)) :- X =< Root, aBBInsertar(X, Izq, NuevoIzq).  
aBBInsertar(X, bin(Izq, Root, Der), bin(Izq, Root, NuevoDer)) :- X > Root, aBBInsertar(X, Der, NuevoDer).  
aBBInsertar(X, bin(Izq, Root, Der), bin(Izq, Root, NuevoDer)) :- X > Root, aBBInsertar(X, Der, NuevoDer).  




Línea 398: Línea 398:


%in_range(+Min, +Max, -Num).  
%in_range(+Min, +Max, -Num).  
in_range(Min, Max, Min) :- Min =< Max.  
in_range(Min, Max, Min) :- Min =< Max.  
in_range(Min, Max, N) :- Min =< Max, NextMin is Min + 1, in_range(NextMin, Max, N).  
in_range(Min, Max, N) :- Min =< Max, NextMin is Min + 1, in_range(NextMin, Max, N).  


valor(hoja(V), V).  
valor(hoja(V), V).  
valor(nodo(V, _), V).  
valor(nodo(V, _), V).  


mayores(hoja(V), Max) :- in_range(0, Max, V).  
mayores(hoja(V), Max) :- in_range(0, Max, V).  
mayores(nodo(V, [X]), Max) :- valor(X, Val), in_range(0, Max, Val), Val1 is Val + 1, in_range(Val1, Max, V).  
mayores(nodo(V, [X]), Max) :- valor(X, Val), in_range(0, Max, Val), Val1 is Val + 1, in_range(Val1, Max, V).  
mayores(nodo(V, [X, Y | T]), Max) :- valor(X, Val), in_range(0, Max, Val), Val1 is Val + 1, in_range(Val1, Max, V),  
mayores(nodo(V, [X, Y | T]), Max) :- valor(X, Val), in_range(0, Max, Val), Val1 is Val + 1, in_range(Val1, Max, V),  
VMenosX is V - Val, mayores(nodo(VMenosX, [Y | T]), Max).  
VMenosX is V - Val, mayores(nodo(VMenosX, [Y | T]), Max).  


%mayores no anda bien, no hace la suma de todos los subhijos, sino de los inmediatos... como se hace bien? facilmente?  
%mayores no anda bien, no hace la suma de todos los subhijos, sino de los inmediatos... como se hace bien? facilmente?  
Línea 427: Línea 427:


%in_range(+Min, +Max, -Min).  
%in_range(+Min, +Max, -Min).  
in_range(Min, Max, Min) :- Min =< Max.  
in_range(Min, Max, Min) :- Min =< Max.  
in_range(Min, Max, N) :- Min =< Max, NextMin is Min + 1, in_range(NextMin, Max, N).  
in_range(Min, Max, N) :- Min =< Max, NextMin is Min + 1, in_range(NextMin, Max, N).  


%combinador(+L, +D, +H, -XS).  
%combinador(+L, +D, +H, -XS).  
combinador(0, _, _, []).  
combinador(0, _, _, []).  
combinador(L, Min, Max, [H | T]) :- L > 0, in_range(Min, Max, H), L1 is L - 1, combinador(L1, Min, Max, T).  
combinador(L, Min, Max, [H | T]) :- L > 0, in_range(Min, Max, H), L1 is L - 1, combinador(L1, Min, Max, T).  


==Ejercicio 17==
==Ejercicio 17==
Línea 459: Línea 459:


%desde(+Desde, -Numero).  
%desde(+Desde, -Numero).  
desde(D, D).  
desde(D, D).  
desde(D, X) :- DD is D+1, desde(DD, X).  
desde(D, X) :- DD is D+1, desde(DD, X).  


%lista_semi_latina(+Longuitud, +Suma, -Lista).  
%lista_semi_latina(+Longuitud, +Suma, -Lista).  
lista_semi_latina(0, 0, []).  
lista_semi_latina(0, 0, []).  
lista_semi_latina(Long, Suma, [H | T]) :- Long > 0, Suma >= 0, Long1 is Long - 1, in_range(0, Suma, H),  
lista_semi_latina(Long, Suma, [H | T]) :- Long > 0, Suma >= 0, Long1 is Long - 1, in_range(0, Suma, H),  
NuevaSuma is Suma - H, lista_semi_latina(Long1, NuevaSuma, T).  
NuevaSuma is Suma - H, lista_semi_latina(Long1, NuevaSuma, T).  


%rectanguloSemiLatino(+Columnas, +Filas, +Suma, -XS).  
%rectanguloSemiLatino(+Columnas, +Filas, +Suma, -XS).  
rectanguloSemiLatino(_, 0, Suma, []) :- Suma >= 0.  
rectanguloSemiLatino(_, 0, Suma, []) :- Suma >= 0.  
rectanguloSemiLatino(Columnas, Filas, Suma, [H | T]) :- Filas > 0, Filas1 is Filas - 1, lista_semi_latina(Columnas, Suma, H),  
rectanguloSemiLatino(Columnas, Filas, Suma, [H | T]) :- Filas > 0, Filas1 is Filas - 1, lista_semi_latina(Columnas, Suma, H),  
rectanguloSemiLatino(Columnas, Filas1, Suma, T).  
rectanguloSemiLatino(Columnas, Filas1, Suma, T).  


%cuadradoSemiLatino(+N, -XS).  
%cuadradoSemiLatino(+N, -XS).  
cuadradoSemiLatino(N, X) :- desde(0, Suma), rectanguloSemiLatino(N, N, Suma, X).  
cuadradoSemiLatino(N, X) :- desde(0, Suma), rectanguloSemiLatino(N, N, Suma, X).  


==Ejercicio 18==
==Ejercicio 18==
Línea 485: Línea 485:


%personas(+Agenda, -Personas).  
%personas(+Agenda, -Personas).  
personas(agenda(Personas), Personas).  
personas(agenda(Personas), Personas).  


%edad(+Agenda, +Persona, -Edad).  
%edad(+Agenda, +Persona, -Edad).  
edad(agenda([persona(Nombre, Edad) | _]), Nombre, Edad).  
edad(agenda([persona(Nombre, Edad) | _]), Nombre, Edad).  
edad(agenda([persona(OtroNombre, Edad) | Resto]), Nombre, Edad) :- OtroNombre \= Nombre,  
edad(agenda([persona(OtroNombre, Edad) | Resto]), Nombre, Edad) :- OtroNombre \= Nombre,  
edad(agenda(Resto), Nombre, Edad).  
edad(agenda(Resto), Nombre, Edad).  
subconjuntos_personas(agenda([]), []).  
subconjuntos_personas(agenda([]), []).  
subconjuntos_personas(agenda([H | T]), [H | Sub]) :- subconjuntos_personas(agenda(T), Sub).  
subconjuntos_personas(agenda([H | T]), [H | Sub]) :- subconjuntos_personas(agenda(T), Sub).  
subconjuntos_personas(agenda([_ | T]), Sub) :- subconjuntos_personas(agenda(T), Sub).  
subconjuntos_personas(agenda([_ | T]), Sub) :- subconjuntos_personas(agenda(T), Sub).  


%promedio_edades(Personas, Edad).  
%promedio_edades(Personas, Edad).  
suma_edades([persona(_, Edad)], Edad).  
suma_edades([persona(_, Edad)], Edad).  
suma_edades([persona(_, Edad) | T], Suma) :- suma_edades(T, SumaT), Suma is SumaT + Edad.  
suma_edades([persona(_, Edad) | T], Suma) :- suma_edades(T, SumaT), Suma is SumaT + Edad.  


%personasEnPromedio(+Agenda, +Edad, -Conjunto).  
%personasEnPromedio(+Agenda, +Edad, -Conjunto).  
personasEnPromedio(Agenda, Edad, Conjunto) :- subconjuntos_personas(Agenda, Conjunto), suma_edades(Conjunto, Suma),  
personasEnPromedio(Agenda, Edad, Conjunto) :- subconjuntos_personas(Agenda, Conjunto), suma_edades(Conjunto, Suma),  
length(Conjunto, Cantidad), Promedio is (Suma // Cantidad), Edad > Promedio.  
length(Conjunto, Cantidad), Promedio is (Suma // Cantidad), Edad > Promedio.  


%caso: personasEnPromedio(agenda([persona(0, 0), persona(0, 1), persona(0, 2), persona(0, 3), persona(0, 4), persona(0, 5)]), 0, X).  
%caso: personasEnPromedio(agenda([persona(0, 0), persona(0, 1), persona(0, 2), persona(0, 3), persona(0, 4), persona(0, 5)]), 0, X).  
Línea 519: Línea 519:


%es_estaca(+E).  
%es_estaca(+E).  
es_estaca(a).  
es_estaca(a).  
es_estaca(b).  
es_estaca(b).  
es_estaca(c).  
es_estaca(c).  


%estacas_diferentes(-E1, -E2, -E3).  
%estacas_diferentes(-E1, -E2, -E3).  
estacas_diferentes(a, b, c).  
estacas_diferentes(a, b, c).  
estacas_diferentes(a, c, b).  
estacas_diferentes(a, c, b).  
estacas_diferentes(b, a, c).  
estacas_diferentes(b, a, c).  
estacas_diferentes(b, c, a).  
estacas_diferentes(b, c, a).  
estacas_diferentes(c, a, b).  
estacas_diferentes(c, a, b).  
estacas_diferentes(c, b, a).  
estacas_diferentes(c, b, a).  


%hanoi_mover(+N, +Desde, +Hasta, -Movimientos).  
%hanoi_mover(+N, +Desde, +Hasta, -Movimientos).  
hanoi_mover(0, Desde, Hasta, []) :- es_estaca(Desde), es_estaca(Hasta).  
hanoi_mover(0, Desde, Hasta, []) :- es_estaca(Desde), es_estaca(Hasta).  
hanoi_mover(N, Desde, Hasta, Movimientos) :- N > 0, N1 is N - 1, estacas_diferentes(Desde, Hasta, Otra),  
hanoi_mover(N, Desde, Hasta, Movimientos) :- N > 0, N1 is N - 1, estacas_diferentes(Desde, Hasta, Otra),  
hanoi_mover(N1, Desde, Otra, MovsDesdeOtra),  
hanoi_mover(N1, Desde, Otra, MovsDesdeOtra),  
hanoi_mover(N1, Otra, Hasta, MovsOtraHasta),  
hanoi_mover(N1, Otra, Hasta, MovsOtraHasta),  
append(MovsDesdeOtra, [mov(Desde, Hasta) | MovsOtraHasta], Movimientos).  
append(MovsDesdeOtra, [mov(Desde, Hasta) | MovsOtraHasta], Movimientos).  


%hanoi(+N, -Movimientos).  
%hanoi(+N, -Movimientos).  
hanoi(N, Movimientos) :- hanoi_mover(N, a, c, Movimientos).  
hanoi(N, Movimientos) :- hanoi_mover(N, a, c, Movimientos).  


==Funciones Varias==
==Funciones Varias==
Línea 546: Línea 546:
% Requiere: true.  
% Requiere: true.  
% Asegura: Lista es una lista que contiene solamente a Elem (cero o mas veces).  
% Asegura: Lista es una lista que contiene solamente a Elem (cero o mas veces).  
repeat(_, []).  
repeat(_, []).  
repeat(Elem, [Elem | Tail]) :- repeat(Elem, Tail).  
repeat(Elem, [Elem | Tail]) :- repeat(Elem, Tail).  


%multi_length(-Lista_de_Listas, -Lista_de_Longuitudes).  
%multi_length(-Lista_de_Listas, -Lista_de_Longuitudes).  
% Requiere: Lista_de_Listas es una lista de listas, y Lista_de_Longuitudes es una lista de naturales.  
% Requiere: Lista_de_Listas es una lista de listas, y Lista_de_Longuitudes es una lista de naturales.  
% Asegura: Lista_de_Longuitudes es una lista que contiene las longuitudes de los elementos de Lista_de_Listas.  
% Asegura: Lista_de_Longuitudes es una lista que contiene las longuitudes de los elementos de Lista_de_Listas.  
multi_length([], []).  
multi_length([], []).  
multi_length([X | XS], [L | LS]) :- length(X, L), multi_length(XS, LS).  
multi_length([X | XS], [L | LS]) :- length(X, L), multi_length(XS, LS).  


%multi_append(-Lista_de_Listas, -Listas_Unidas).  
%multi_append(-Lista_de_Listas, -Listas_Unidas).  
Línea 559: Línea 559:
% Asegura: Listas_Unidas son todas las listas de la listas unidas,  
% Asegura: Listas_Unidas son todas las listas de la listas unidas,  
% en el orden en que aparecian en la lista de listas.  
% en el orden en que aparecian en la lista de listas.  
multi_append([], []).  
multi_append([], []).  
multi_append([[X] | YS], [X | ZS]) :- multi_append(YS, ZS).  
multi_append([[X] | YS], [X | ZS]) :- multi_append(YS, ZS).  
multi_append([[X1, X2 | XS] | YS], [X1 | ZS]) :- multi_append([[X2 | XS] | YS], ZS).  
multi_append([[X1, X2 | XS] | YS], [X1 | ZS]) :- multi_append([[X2 | XS] | YS], ZS).  


%particion_doble(-Parte1, -Parte2, -Lista).  
%particion_doble(-Parte1, -Parte2, -Lista).  
Línea 567: Línea 567:
% Asegura: Parte1 y Parte2 son una particion de Lista en dos listas,  
% Asegura: Parte1 y Parte2 son una particion de Lista en dos listas,  
% preservando en ellas el orden relativo original de los elementos.  
% preservando en ellas el orden relativo original de los elementos.  
particion_doble([], [], []).  
particion_doble([], [], []).  
particion_doble([X | XS], [], [X | XS]).  
particion_doble([X | XS], [], [X | XS]).  
particion_doble([], [Y | YS], [Y | YS]).  
particion_doble([], [Y | YS], [Y | YS]).  
particion_doble([X | XS], [Y | YS], [X | ZS]) :- particion_doble(XS, [Y | YS], ZS).  
particion_doble([X | XS], [Y | YS], [X | ZS]) :- particion_doble(XS, [Y | YS], ZS).  
particion_doble([X | XS], [Y | YS], [Y | ZS]) :- particion_doble([X | XS], YS, ZS).  
particion_doble([X | XS], [Y | YS], [Y | ZS]) :- particion_doble([X | XS], YS, ZS).  


%particion_doble_sin_vacio(-Parte1, -Parte2, -Lista).  
%particion_doble_sin_vacio(-Parte1, -Parte2, -Lista).  
Línea 577: Línea 577:
% Asegura: Parte1 y Parte2 son una particion de Lista en dos listas (ninguna vacia),  
% Asegura: Parte1 y Parte2 son una particion de Lista en dos listas (ninguna vacia),  
% preservando en ellas el orden relativo original de los elementos.  
% preservando en ellas el orden relativo original de los elementos.  
particion_doble_sin_vacio([X], [Y | YS], [X, Y | YS]).  
particion_doble_sin_vacio([X], [Y | YS], [X, Y | YS]).  
particion_doble_sin_vacio([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_sin_vacio([X2 | XS], [Y | YS], ZS).  
particion_doble_sin_vacio([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_sin_vacio([X2 | XS], [Y | YS], ZS).  
particion_doble_sin_vacio([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_sin_vacio([Y | YS], [X2 | XS], ZS).  
particion_doble_sin_vacio([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_sin_vacio([Y | YS], [X2 | XS], ZS).  


%particion(-ListaDeSublistas, +Lista).  
%particion(-ListaDeSublistas, +Lista).  
% Requiere: Lista es una Lista, ListaDeSublistas una lista de listas.  
% Requiere: Lista es una Lista, ListaDeSublistas una lista de listas.  
% Asegura: ListaDeSublistas es una lista de sublistas disjuntas que forman Lista.  
% Asegura: ListaDeSublistas es una lista de sublistas disjuntas que forman Lista.  
particion([], []).  
particion([], []).  
particion( XS, [X | XS]).  
particion( XS, [X | XS]).  
particion([[X | XS], Y | YS], ZS) :- particion_doble_sin_vacio([X | XS], PS, ZS).  
particion([[X | XS], Y | YS], ZS) :- particion_doble_sin_vacio([X | XS], PS, ZS).  




Línea 592: Línea 592:
% Requiere: Lista es una Lista de longuitud multiplo de Longuitud, ListaDeSublistas una lista de listas.  
% Requiere: Lista es una Lista de longuitud multiplo de Longuitud, ListaDeSublistas una lista de listas.  
% Asegura: ListaDeSublistas es una lista de sublistas disjuntas que forman Lista cada una de longuitud Longuitud.  
% Asegura: ListaDeSublistas es una lista de sublistas disjuntas que forman Lista cada una de longuitud Longuitud.  
particion_de_longuitud_n(Lista, Longuitud, ListaDeSublistas) :- particion(ListaDeSublistas, Lista),  
particion_de_longuitud_n(Lista, Longuitud, ListaDeSublistas) :- particion(ListaDeSublistas, Lista),  
length(Lista, Length_Lista), Cantidad is Length_Lista // Longuitud,  
length(Lista, Length_Lista), Cantidad is Length_Lista // Longuitud,  
repeat(Longuitud, Lista_Longs), length(Lista_Longs, Cantidad),  
repeat(Longuitud, Lista_Longs), length(Lista_Longs, Cantidad),  
multi_length(ListaDeSublistas, Lista_Longs).  
multi_length(ListaDeSublistas, Lista_Longs).  


%lista_de_grupos(+Lista_de_Paises_en_Grupos, +Ids, -Grupos).  
%lista_de_grupos(+Lista_de_Paises_en_Grupos, +Ids, -Grupos).  
lista_de_grupos([], [], []).  
lista_de_grupos([], [], []).  
lista_de_grupos([P | PS], [I | IS], [grupo(I, P) | GS]) :- lista_de_grupos(PS, IS, GS).  
lista_de_grupos([P | PS], [I | IS], [grupo(I, P) | GS]) :- lista_de_grupos(PS, IS, GS).  
% Requiere: length(Lista_de_Paises_en_Grupos) == length(Ids).  
% Requiere: length(Lista_de_Paises_en_Grupos) == length(Ids).  
% Asegura: Grupos es la formacion de grupos asignando un id a cada grupo de paises de la lista.  
% Asegura: Grupos es la formacion de grupos asignando un id a cada grupo de paises de la lista.  


%mesclar_particiones_de_listas(-Particiones, +Listas_de_Listas).  
%mesclar_particiones_de_listas(-Particiones, +Listas_de_Listas).  
grupos(Ps, Ids, Grupos) :- lista_de_grupos(Lista_de_Paises_en_Grupos, Ids, Grupos).  
grupos(Ps, Ids, Grupos) :- lista_de_grupos(Lista_de_Paises_en_Grupos, Ids, Grupos).  


%grupos(+Ps, +Ids, -Grupos)  
%grupos(+Ps, +Ids, -Grupos)  
grupos(Ps, Ids, Grupos) :- lista_de_grupos(Lista_de_Paises_en_Grupos, Ids, Grupos).  
grupos(Ps, Ids, Grupos) :- lista_de_grupos(Lista_de_Paises_en_Grupos, Ids, Grupos).  


paises([[argentina, brasil], [mejico,canada],  
paises([[argentina, brasil], [mejico,canada],  
[sudafrica, egipto]]).  
[sudafrica, egipto]]).  
listas([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]).  
listas([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]).  
listas2([1, 2, 3]).  
listas2([1, 2, 3]).  


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
Línea 619: Línea 619:


%es_natural(-Numero).  
%es_natural(-Numero).  
es_natural(0).  
es_natural(0).  
es_natural(N) :- es_natural(N1), N is N1 + 1.  
es_natural(N) :- es_natural(N1), N is N1 + 1.  


%es_positivo(-Numero).  
%es_positivo(-Numero).  
es_positivo(1).  
es_positivo(1).  
es_positivo(N) :- es_natural(N1), N is N1 + 1.  
es_positivo(N) :- es_natural(N1), N is N1 + 1.  


%es_negativo(-Numero).  
%es_negativo(-Numero).  
es_negativo(-1).  
es_negativo(-1).  
es_negativo(N) :- es_negativo(N1), N is N1 - 1.  
es_negativo(N) :- es_negativo(N1), N is N1 - 1.  


%diferencia_con_siguiente_entero(-Signo, +Numero).  
%diferencia_con_siguiente_entero(-Signo, +Numero).  
diferencia_con_siguiente_entero(1, 0).  
diferencia_con_siguiente_entero(1, 0).  
diferencia_con_siguiente_entero(1, N) :- N > 0.  
diferencia_con_siguiente_entero(1, N) :- N > 0.  
diferencia_con_siguiente_entero(0, N) :- N < 0.  
diferencia_con_siguiente_entero(0, N) :- N < 0.  


%es_entero(-Signo, +Numero).  
%es_entero(-Signo, +Numero).  
es_entero(0).  
es_entero(0).  
es_entero(N) :- es_entero(M), NM is -M, diferencia_con_siguiente_entero(S, NM),  
es_entero(N) :- es_entero(M), NM is -M, diferencia_con_siguiente_entero(S, NM),  
N is NM + S.  
N is NM + S.  


%signo_aux(-Signo, +Numero).  
%signo_aux(-Signo, +Numero).  
signo_aux(0, 0).  
signo_aux(0, 0).  
signo_aux(1, N) :- N > 0.  
signo_aux(1, N) :- N > 0.  
signo_aux(-1, N) :- N < 0.  
signo_aux(-1, N) :- N < 0.  


%signo(-Signo, -Numero).  
%signo(-Signo, -Numero).  
signo(0, 0).  
signo(0, 0).  
signo(S, N) :- es_entero(N), N \= 0, signo_aux(S, N).  
signo(S, N) :- es_entero(N), N \= 0, signo_aux(S, N).  


%en_rango(-Numero, +Desde, +Hasta).  
%en_rango(-Numero, +Desde, +Hasta).  
en_rango(D, D, H) :- D =< H.  
en_rango(D, D, H) :- D =< H.  
en_rango(N, D, H) :- D =< H, ND is D + 1, en_rango(N, ND, H).  
en_rango(N, D, H) :- D =< H, ND is D + 1, en_rango(N, ND, H).  


%desde(-Numero, +Desde).  
%desde(-Numero, +Desde).  
desde(D, D).  
desde(D, D).  
desde(N, D) :- DD is D+1, desde(N, DD).  
desde(N, D) :- DD is D+1, desde(N, DD).  


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
Línea 666: Línea 666:


%es_arbol_de_altura(-Arbol, +Altura).  
%es_arbol_de_altura(-Arbol, +Altura).  
es_arbol_de_altura(nil, 0).  
es_arbol_de_altura(nil, 0).  
es_arbol_de_altura(bin(I, _, D), H) :- H > 0, H1 is H - 1,  
es_arbol_de_altura(bin(I, _, D), H) :- H > 0, H1 is H - 1,  
en_rango(HI, 0, H1),  
en_rango(HI, 0, H1),  
en_rango(HD, 0, H1), H1 is max(HD, HI),  
en_rango(HD, 0, H1), H1 is max(HD, HI),  
es_arbol_de_altura(I, HI), es_arbol_de_altura(D, HD).  
es_arbol_de_altura(I, HI), es_arbol_de_altura(D, HD).  


%altura(-Arbol, -Altura).  
%altura(-Arbol, -Altura).  
altura(A, H) :- es_natural(H), es_arbol_de_altura(A, H).  
altura(A, H) :- es_natural(H), es_arbol_de_altura(A, H).  


%preorder_de_arboles(-Nodos, -Arbol).  
%preorder_de_arboles(-Nodos, -Arbol).  
preorder_de_arboles([], []).  
preorder_de_arboles([], []).  
preorder_de_arboles(L, [nil | AS]) :- preorder_de_arboles(L, AS).  
preorder_de_arboles(L, [nil | AS]) :- preorder_de_arboles(L, AS).  
preorder_de_arboles([X | XS], [bin(I, X, D) | AS]) :- preorder_de_arboles(XS, [I, D | AS]).  
preorder_de_arboles([X | XS], [bin(I, X, D) | AS]) :- preorder_de_arboles(XS, [I, D | AS]).  


%preorder(-Nodos, -Arbol).  
%preorder(-Nodos, -Arbol).  
preorder(L, A) :- preorder_de_arboles(L, [A]).  
preorder(L, A) :- preorder_de_arboles(L, [A]).  


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
Línea 696: Línea 696:
% de ListaDeListas y Resto es lo que queda despues de sacar eso.  
% de ListaDeListas y Resto es lo que queda despues de sacar eso.  
% Uso:  
% Uso:  
map_tomar_uno_de_lista([], [], []).  
map_tomar_uno_de_lista([], [], []).  
map_tomar_uno_de_lista([H | T], [R | RS], [L | LS]) :- particion_doble_unicas_vacia([H], R, L),  
map_tomar_uno_de_lista([H | T], [R | RS], [L | LS]) :- particion_doble_unicas_vacia([H], R, L),  
map_tomar_uno_de_lista(T, RS, LS).  
map_tomar_uno_de_lista(T, RS, LS).  


% particion(-ListaDeSublistas, +Lista).  
% particion(-ListaDeSublistas, +Lista).  
Línea 710: Línea 710:
% Asegura: Parte1 y Parte2 son una particion de Lista en dos listas (ninguna vacia),  
% Asegura: Parte1 y Parte2 son una particion de Lista en dos listas (ninguna vacia),  
% preservando en ellas el orden relativo original de los elementos.  
% preservando en ellas el orden relativo original de los elementos.  
particion_doble_unicas([X], [Y | YS], [X, Y | YS]).  
particion_doble_unicas([X], [Y | YS], [X, Y | YS]).  
particion_doble_unicas([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_unicas([X2 | XS], [Y | YS], ZS).  
particion_doble_unicas([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_unicas([X2 | XS], [Y | YS], ZS).  
particion_doble_unicas([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_unicas([Y | YS], [X2 | XS], ZS).  
particion_doble_unicas([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_unicas([Y | YS], [X2 | XS], ZS).  


% particiones_de_longuitud_n(-ListaDeSublistas, +Longuitud, +Lista)  
% particiones_de_longuitud_n(-ListaDeSublistas, +Longuitud, +Lista)  
% Requiere: true.  
% Requiere: true.  
% Asegura: ListaDeSublistas es una lista de sublistas disjuntas que forman Lista cada una de longuitud Longuitud.  
% Asegura: ListaDeSublistas es una lista de sublistas disjuntas que forman Lista cada una de longuitud Longuitud.  
particiones_de_longuitud_n([XS], L, XS) :- length(XS, L).  
particiones_de_longuitud_n([XS], L, XS) :- length(XS, L).  
particiones_de_longuitud_n([X | XS], L, ZS) :- not(length(ZS, L)), particion_doble_unicas(X, YS, ZS), length(X, L),  
particiones_de_longuitud_n([X | XS], L, ZS) :- not(length(ZS, L)), particion_doble_unicas(X, YS, ZS), length(X, L),  
particiones_de_longuitud_n(XS, L, YS).  
particiones_de_longuitud_n(XS, L, YS).  


% map_particiones_de_longuitud_n(-Sublistas, +CantidadDeGrupos, +Listas)  
% map_particiones_de_longuitud_n(-Sublistas, +CantidadDeGrupos, +Listas)  
% Requiere: true.  
% Requiere: true.  
% Asegura: similar a Haskell: map particiones_de_longuitud_n.  
% Asegura: similar a Haskell: map particiones_de_longuitud_n.  
map_particiones_de_longuitud_n([], N, []) :- N > 0.  
map_particiones_de_longuitud_n([], N, []) :- N > 0.  
map_particiones_de_longuitud_n([X | XS], N, [Y | YS]) :- map_particiones_de_longuitud_n(XS, N, YS),  
map_particiones_de_longuitud_n([X | XS], N, [Y | YS]) :- map_particiones_de_longuitud_n(XS, N, YS),  
particiones_de_longuitud_n(X, N, Y).  
particiones_de_longuitud_n(X, N, Y).  


% iesimos_elementos(-Iesimos, +Indice, -ListaDeListas)  
% iesimos_elementos(-Iesimos, +Indice, -ListaDeListas)  
% Requiere: true.  
% Requiere: true.  
% Asegura: Iesimos son los iesimos elementos de cada lista de ListaDeListas.  
% Asegura: Iesimos son los iesimos elementos de cada lista de ListaDeListas.  
iesimos_elementos([], N, []) :- N >= 0.  
iesimos_elementos([], N, []) :- N >= 0.  
iesimos_elementos([E | XS], I, [Y | YS]) :- nth0(I, Y, E), iesimos_elementos(XS, I, YS).  
iesimos_elementos([E | XS], I, [Y | YS]) :- nth0(I, Y, E), iesimos_elementos(XS, I, YS).  




% generar_listas_tomando_de_listas_entre_iesimos(-Reordenado, +Desde, +Hasta, +ListaDeListas)  
% generar_listas_tomando_de_listas_entre_iesimos(-Reordenado, +Desde, +Hasta, +ListaDeListas)  
generar_listas_tomando_de_listas_entre_iesimos([], D, H, L) :- D > H, is_list(L).  
generar_listas_tomando_de_listas_entre_iesimos([], D, H, L) :- D > H, is_list(L).  
generar_listas_tomando_de_listas_entre_iesimos([X | XS], D, H, YS) :- D =< H, D1 is D + 1, iesimos_elementos(X, D, YS),  
generar_listas_tomando_de_listas_entre_iesimos([X | XS], D, H, YS) :- D =< H, D1 is D + 1, iesimos_elementos(X, D, YS),  
generar_listas_tomando_de_listas_entre_iesimos(XS, D1, H, YS).  
generar_listas_tomando_de_listas_entre_iesimos(XS, D1, H, YS).  


% last(+N, -Tail, -Lista).  
% last(+N, -Tail, -Lista).  
% Requiere: true.  
% Requiere: true.  
% Asegura: Tail son los ultimos n elementos de Lista.  
% Asegura: Tail son los ultimos n elementos de Lista.  
last(N, Tail, Lista) :- length(Tail, N), append(_, Tail, Lista).  
last(N, Tail, Lista) :- length(Tail, N), append(_, Tail, Lista).  


% sin_iesimo(-ListaSinIesimo, -Indice, -Lista)  
% sin_iesimo(-ListaSinIesimo, -Indice, -Lista)  
% Requiere: true  
% Requiere: true  
% Asegura: ListaSinIesimo es la lista sin el elemento en la posicion Indice de Lista.  
% Asegura: ListaSinIesimo es la lista sin el elemento en la posicion Indice de Lista.  
sin_iesimo(NL, I, L) :- append(Init, [_ | Tail], L), length(Init, I), append(Init, Tail, NL).  
sin_iesimo(NL, I, L) :- append(Init, [_ | Tail], L), length(Init, I), append(Init, Tail, NL).  


% sin_primera_aparicion(-ListaSinElemento, -Elemento, -Lista)  
% sin_primera_aparicion(-ListaSinElemento, -Elemento, -Lista)  
% Requiere: true.  
% Requiere: true.  
% Asegura: ListaSinElemento es igual a Lista sin la primera aparicion del elemento.  
% Asegura: ListaSinElemento es igual a Lista sin la primera aparicion del elemento.  
sin_primera_aparicion(ZS, E, L) :- append(ZS1, [E | ZS2], L), append(ZS1, ZS2, ZS), not(member(E, ZS1)).  
sin_primera_aparicion(ZS, E, L) :- append(ZS1, [E | ZS2], L), append(ZS1, ZS2, ZS), not(member(E, ZS1)).  


% concat(-Lista_de_Listas, -Listas_Unidas).  
% concat(-Lista_de_Listas, -Listas_Unidas).  
Línea 759: Línea 759:
% Asegura: Listas_Unidas son todas las listas de la listas unidas,  
% Asegura: Listas_Unidas son todas las listas de la listas unidas,  
% en el orden en que aparecian en la lista de listas.  
% en el orden en que aparecian en la lista de listas.  
concat([], []).  
concat([], []).  
concat([[X] | YS], [X | ZS]) :- concat(YS, ZS).  
concat([[X] | YS], [X | ZS]) :- concat(YS, ZS).  
concat([[X1, X2 | XS] | YS], [X1 | ZS]) :- concat([[X2 | XS] | YS], ZS).  
concat([[X1, X2 | XS] | YS], [X1 | ZS]) :- concat([[X2 | XS] | YS], ZS).  


% map_concat(-ListaDeListasDeListas, +ListasMappeadas)  
% map_concat(-ListaDeListasDeListas, +ListasMappeadas)  
% Requiere: true.  
% Requiere: true.  
% Asegura: similar a Haskell: map concat  
% Asegura: similar a Haskell: map concat  
map_concat([], []).  
map_concat([], []).  
map_concat([X | XS], [Y | YS]) :- concat(X, Y), map_concat(XS, YS).  
map_concat([X | XS], [Y | YS]) :- concat(X, Y), map_concat(XS, YS).  


% take(+N, -Tail, -Lista).  
% take(+N, -Tail, -Lista).  
Línea 773: Línea 773:
% Asegura: Tail son los elementos que quedan luego de sacar los n primeros  
% Asegura: Tail son los elementos que quedan luego de sacar los n primeros  
% elementos a Lista.  
% elementos a Lista.  
drop(N, Tail, Lista) :- length(Init, N), append(Init, Tail, Lista).  
drop(N, Tail, Lista) :- length(Init, N), append(Init, Tail, Lista).  


% pertenece(-Elemento, -Lista)  
% pertenece(-Elemento, -Lista)  
% Requiere: true  
% Requiere: true  
% Asegura: Elemento pertenece a Lista.  
% Asegura: Elemento pertenece a Lista.  
pertenece(E, L) :- append(_, [E | _], L).  
pertenece(E, L) :- append(_, [E | _], L).  


% sin_un_elemento(-ListaSinElemento, -Elemento, -Lista)  
% sin_un_elemento(-ListaSinElemento, -Elemento, -Lista)  
% Requiere: true.  
% Requiere: true.  
% Asegura: ListaSinElemento es igual a Lista sin una vez ese elemento.  
% Asegura: ListaSinElemento es igual a Lista sin una vez ese elemento.  
sin_un_elemento(ZS, E, L) :- append(ZS1, [E | ZS2], L), append(ZS1, ZS2, ZS).  
sin_un_elemento(ZS, E, L) :- append(ZS1, [E | ZS2], L), append(ZS1, ZS2, ZS).  


% sin_elemento(-ListaSinElementos, +Elemento, +Lista)  
% sin_elemento(-ListaSinElementos, +Elemento, +Lista)  
% Requiere: true.  
% Requiere: true.  
% Asegura: ListaSinElementos es igual a Lista sin todas las apariciones del elemento.  
% Asegura: ListaSinElementos es igual a Lista sin todas las apariciones del elemento.  
sin_elemento([], _, []).  
sin_elemento([], _, []).  
sin_elemento(L, H, [H | T]) :- sin_elemento(L, H, T).  
sin_elemento(L, H, [H | T]) :- sin_elemento(L, H, T).  
sin_elemento([H | L], E, [H | T]) :- E \= H, sin_elemento(L, E, T).  
sin_elemento([H | L], E, [H | T]) :- E \= H, sin_elemento(L, E, T).  


% iesimo(-Elemento, -Indice, -Lista)  
% iesimo(-Elemento, -Indice, -Lista)  
% Requiere: true  
% Requiere: true  
% Asegura: Elemento es el elemento en la posicion Indice de Lista.  
% Asegura: Elemento es el elemento en la posicion Indice de Lista.  
iesimo(E, I, L) :- append(Init, [E | _], L), length(Init, I).  
iesimo(E, I, L) :- append(Init, [E | _], L), length(Init, I).  


% interseccion(-Interseccion, +ListaL, +ListaR)  
% interseccion(-Interseccion, +ListaL, +ListaR)  
Línea 801: Línea 801:
% Asegura: Interseccion es la interseccion sin duplicados de ListaL y ListaR  
% Asegura: Interseccion es la interseccion sin duplicados de ListaL y ListaR  
% manteniendo el orden de los elementos en ListaL.  
% manteniendo el orden de los elementos en ListaL.  
interseccion([], [], []).  
interseccion([], [], []).  
interseccion([E | ZS], [E | LL], LRE) :- member(E, LRE), delete(LRE, E, LR),  
interseccion([E | ZS], [E | LL], LRE) :- member(E, LRE), delete(LRE, E, LR),  
interseccion(ZS, LL, LR).  
interseccion(ZS, LL, LR).  
interseccion(ZS, [E | LL], LR) :- not(member(E, LR)), interseccion(ZS, LL, LR).  
interseccion(ZS, [E | LL], LR) :- not(member(E, LR)), interseccion(ZS, LL, LR).  


% sin_repetidos(-ListaSinRepetidos, +Lista).  
% sin_repetidos(-ListaSinRepetidos, +Lista).  
% Requiere: true.  
% Requiere: true.  
% Asegura: ListaSinRepetidos es igual a Lista solo que no tiene repetidos.  
% Asegura: ListaSinRepetidos es igual a Lista solo que no tiene repetidos.  
sin_repetidos([], []).  
sin_repetidos([], []).  
sin_repetidos([E | XS], [E | YS]) :- not(member(E, YS)), sin_repetidos(XS, YS).  
sin_repetidos([E | XS], [E | YS]) :- not(member(E, YS)), sin_repetidos(XS, YS).  
sin_repetidos(XS, [E | YS]) :- member(E, YS), sin_repetidos(XS, YS).  
sin_repetidos(XS, [E | YS]) :- member(E, YS), sin_repetidos(XS, YS).  
sin_repetidos([E | XS], [E | YS]) :- member(E, YS), sin_repetidos(XSE, YS),  
sin_repetidos([E | XS], [E | YS]) :- member(E, YS), sin_repetidos(XSE, YS),  
select(E, XSE, XS).  
select(E, XSE, XS).  


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  

Revisión del 19:13 10 may 2008

Plantilla:Back

Ejercicio 01

% A partir de los predicados binarios padre y esposo y de los predicados unarios hombre y mujer, definir % en Prolog los predicados binarios: hijo, abuelo, progenitor, hermano, descendiente, tio.

% i. Considerar el ´arbol geneal´ogico de la siguiente figura. Dibuje el ´arbol de b´usqueda de Prolog % para la consulta abuelo(Who, ron).

%padre(-Padre, -Hijo) %esposo(-Hombre, -Mujer)

padre(john, sue). 
padre(john, bill). 
padre(bob, nancy). 
padre(bob, jeff). 
padre(bill, ron). 
esposo(john, mary). 
esposo(bob, sue). 
esposo(bill, jane). 
hombre(john). 
hombre(bob). 
hombre(jeff). 
hombre(bill). 
hombre(ron). 
mujer(mary). 
mujer(sue). 
mujer(nancy). 
mujer(jane). 

%hijo( -Hijo, -Persona)

hijo(Hijo, Persona) :- hombre(Persona), padre(Persona, Hijo). 
hijo(Hijo, Persona) :- mujer(Persona), esposo(Esposo, Persona), hijo(Hijo, Esposo). 

%abuelo(-Abuelo, -Nieto)

abuelo(Abuelo, Nieto) :- hijo(Nieto, Progenitor), hijo(Progenitor, Abuelo). 

%progenitor(-Progenitor, -Hijo)

progenitor(Progenitor, Hijo) :- hijo(Hijo, Progenitor). 

%hermano(-Hermano, -Persona)

hermano(Hermano, Persona) :- progenitor(Progenitor, Hermano), progenitor(Progenitor, Persona), Hermano \= Persona. 

%descendiente(-Descendiente, -Ascendiente)

descendiente(Descendiente, Ascendiente) :- hijo(Descendiente, Ascendiente). 
descendiente(Descendiente, Ascendiente) :- hijo(Descendiente, Padre), descendiente(Padre, Ascendiente). 

%tio(-Tio, -Sobrino)

tio(Tio, Sobrino) :- hijo(Sobrino, Padre), hermano(Tio, Padre). 

% ii. Defina una nueva relaci´on primo. ¿C´omo se puede definir una consulta para conocer todos los % primos de ron?

%primo(-Primo, -OtroPrimo)

primo(Primo, OtroPrimo) :- abuelo(Abuelo, Primo), abuelo(Abuelo, OtroPrimo), Primo \= OtroPrimo. 

%ii. Respuesta: primo(ron, Primo).

% iii. Considerar el agregado del siguiente hecho y regla: % ancestro(X, X). % ancestro(X, Y) :- ancestro(Z, Y), progenitor(X, Z). % y el ´arbol geneal´ogico del item anterior. % a) Explicar la respuesta a la consulta ancestro(bill, X).

% iii. a. ancestro(bill, X). % iii. a. salida: X = bill; X = ron; Loop Infinito...

% b) Describir las circunstancias en las que puede ocurrir un loop infinito en Prolog.

% c) Sugerir un soluci´on al problema hallado en los puntos anteriores reescribiendo el programa % de ancestro.


% iii. c. ancestro:

ancestro(X, X). 
ancestro(X, Y) :- ancestro(Z, Y), progenitor(X, Z). 


Ejercicio 02

% Usando la definici´on de n´umero natural a partir de cero y sucesor, definir un predicado unario nn, % tal que nn(-X) sii X es un n´umero natural. Definir las siguientes relaciones entre n´umeros naturales:

%data Nat = cero | sucesor Nat

%nn(-X).

nn(cero). 
nn(sucesor(X)) :- nn(X). 
tonn(0, cero). 
tonn(X, sucesor(Y)) :- X > 0, PrevX is X - 1, tonn(PrevX, Y). 

% i. moi(-X, +Y) sii X es menor o igual que Y.

moi(cero, Y) :- nn(Y). 
moi(sucesor(X), sucesor(Y)) :- moi(X, Y). 

% menor(-X, +Y) sii X es menor que Y.

menor(cero, sucesor(Y)) :- nn(Y). 
menor(sucesor(X), sucesor(Y)) :- menor(X, Y). 

% ii. producto(+X, +Y, -Z) sii Z es el producto de X con Y. %suma(-X, -Y, -Z) sii Z es la suma de X con Y.

suma(X, cero, X) :- nn(X). 
suma(X, sucesor(Y), sucesor(Z)) :- suma(X, Y, Z). 

%producto(+X, +Y, -Z)

producto(X, cero, cero) :- nn(X). 
producto(X, sucesor(Y), Z) :- producto(X, Y, XPorY), suma(X, XPorY, Z). 

% iii. fact(+X, -F) sii F es el factorial de X. %iii. fact(+X, -F) sii F es el factorial de X.

fact(cero, sucesor(cero)). 
fact(sucesor(X), F) :- fact(X, PrevF), producto(sucesor(X), PrevF, F). 

%iv. mod(+X, +Y, -Z) sii Z es el resto de la divisi´on entrera entre X e Y. Definicion recursiva.

mod(X, X, cero) :- X \= cero, nn(X). 
mod(X, Y, X) :- Y \= cero, X \= Y, moi(X, Y). 
mod(X, Y, Z) :- Y \= cero, suma(XMenosY, Y, X), mod(XMenosY, Y, Z). 

%iv. modNR(+X, +Y, -Z) sii Z es el resto de la divisi´on entrera entre X e Y. Definicion no recursiva. %Propiedad: Z + K * Y = X

modNR(X, X, cero) :- X \= cero, nn(X). 
modNR(X, Y, X) :- Y \= cero, X \= Y, moi(X, Y). 
modNR(X, Y, Z) :- Y \= cero, moi(K, X), menor(Z, Y), producto(K, Y, CasiX), suma(CasiX, Z, X). 

%v. Definir un predicado unario que determine si un n´umero entero dado es primo. Tener en cuenta que el argumento siempre est´a instanciado.

no_es_primo(cero). 
no_es_primo(sucesor(cero)). 
no_es_primo(X) :- nn(X), menor(Menor, X), menor(sucesor(cero), Menor), mod(X, Menor, cero). 
primo(X) :- not(no_es_primo(X)). 


sumaPrimo(float(Entera1, Dec1), float(Entera2, Dec2)) :- 
sumaPrimo(float(Entera1, Dec1), float(Entera2, Dec2)) :- noventaYNueve(N99), moi(Dec1, N99), moi(Dec2, N99), 
producto(Entera1, suc(N99), Ent1), producto(Entera2, suc(N99), Ent2), 
suma(Ent1, Dec1, Num1), suma(Ent2, Dec2, Num2), moi(Num1, Num2), 
suma(Entera2, Dec2, Primo), primo(Primo). 

Ejercicio 03

Ejercicio 04

% Definir los siguientes predicados:

% i. last(-L, -U), donde U es el ´ultimo elemento de la lista L. Definirlo en forma recursiva, y usando % el predicado append definido de la siguiente manera: % append([], X, X). % append( [H | T], Y, [H | Z]) :- append(T, Y, Z).

last(L, U) :- append(_, [U], L). 

% ii. reverse(+L, -L1), donde L1 contiene los mismos elementos que L, pero en orden inverso. % Ejemplo: reverse([a,b,c], [c,b,a]). % Realizar una definici´on usando append, y otra sin usarlo. Mostrar el ´arbol de prueba para el % ejemplo dado.

% reverse([], []). % reverse([H | T], [ReversedT | [H]]) :- reverse(T, ReversedT). % reverse: como se hace reverse sin append?

reverse2([], []). 
reverse2([H | T], R) :- reverse2(T, ReversedT), append(ReversedT, [H], R). 

% iii. maxlista(+L, -M) y minlista(+L, -M), donde M es el m´aximo/m´inimo de la lista L.

maxlista([H], H). 
maxlista([H | T], H) :- maxlista(T, M), H >= M. 
maxlista([H | T], M) :- maxlista(T, M), H < M. 
minlista([H], H). 
minlista([H | T], H) :- minlista(T, M), H =< M. 
minlista([H | T], M) :- minlista(T, M), H > M. 

% iv. palindromo(+L, -L1), donde L1 es un pal´indromo construido a partir de L. % Ejemplo: palindromo([a,b,c], [a,b,c,c,b,a]).

palindromo(L, P) :- reverse2(L, RevL), append(L, RevL, P). 

% v. doble(-L, -L1), donde cada elemento de L aparece dos veces en L1. % Ejemplo: doble([a,b,c], [a,a,b,b,c,c]).

doble([], []). 
doble([H | T], [H | H | DT]) :- doble(T, DT). 

% vi. prefijo(-P, +L), donde P es prefijo de la lista L.

prefijo(P, L) :- append(P, _, L). 

% vii. sufijo(-S, +L), donde S es sufijo de la lista L.

sufijo(P, L) :- append(_, P, L). 

% viii. sublista(-S, +L), donde S es sublista de L. % Esta version es para sublistas "continuas" en L.

sublista([], _). 
sublista(S, L) :- append(CasiL, _, L), append(_, S, CasiL), S \= []. 

% Esta version es para sublistas "no continuas" en L.

sublistaB([], []). 
sublistaB([H | SubsT], [H | T]) :- sublistaB(SubsT, T). 
sublistaB(SubsT, [_ | T]) :- sublistaB(SubsT, T). 

% ix. iesimo(-I, +L, -X), donde X es el I-´esimo elemento de la lista L. % Ejemplo: iesimo(2, [10, 20, 30, 40], 20).

iesimo(I, L, X) :- append(ListI, [X | _], L), length(ListI, I). 

% Definir los siguientes predicados: % i. mezcla(L1, L2, L3), donde L3 es el resultado de mezclar uno a uno los elementos de las listas % L1 y L2. Si una lista tiene longitud menor, entonces el resto de la lista m´as larga es pasado % sin cambiar. Verificar la reversibilidad, es decir si es posible obtener L3 a partir de L1 y L2, y % viceversa. % Ejemplo: mezcla([a,b,c], [d,e], [a,d,b,e,c]).

mezcla(L1, [], L1). 
mezcla([], L2, L2). 
mezcla([H1 | T1], [H2 | T2], [H1, H2 | T12]) :- mezcla(T1, T2, T12). 

% ii. split(N, L, L1, L2), donde L1 tiene los N primeros elementos de L, y L2 el resto. Si L tiene % menos de N elementos el predicado debe fallar. ¿Cu´an reversible es este predicado? Es decir, % ¿qu´e elementos pueden estar indefinidos al momento de la invocaci´on?

split(N, L, L1, L2) :- append(L1, L2, L), length(L1, N). 

% iii. borrar(+ListaConXs, +X, -ListaSinXs), que elimina todas las ocurrencias de X de la lista % ListaConXs.

borrar([], _, []). 
borrar([H | XS], E, [H | YS]) :- E \= H, borrar(XS, E, YS). 
borrar([E | XS], E, YS) :- borrar(XS, E, YS). 

% iv. sacarDuplicados(+L1, -L2), que saca todos los elementos duplicados de la lista L1.

pertenece(E, L1) :- append(Principio, _, L1), append(_, [E], Principio). 
sacarDuplicados([], []). 
sacarDuplicados([H | T], [H | SinDups]) :- borrar(T, H, BorrarH), sacarDuplicados(BorrarH, SinDups). 
sacarDuplicados([H | T], SinDups) :- pertenece(H, T), sacarDuplicados(T, SinDups). 

%Ejecicio 7 %Definir el predicado aplanar(+Xs, -Ys), que es verdadero sii Ys contiene los elementos contenidos %en alg´un nivel de Xs, en el mismo orden de aparici´on. Los elementos de Xs son enteros, ´atomos o %nuevamente listas, de modo que Xs puede tener una profundidad arbitraria. Por el contrario, Ys es %una lista de un solo nivel de profundidad. %Ejemplos: %?- aplanar([a, [3, b, []], [2]], [a, 3, b, 2]). %?- aplanar([[1, [2, 3], [a]], [[[]]]], [1, 2, 3, a]).

aplanar([], []). 
aplanar([H | T], App) :- is_list(H), aplanar(H, AppH), aplanar(T, AppT), append(AppH, AppT, App). 
aplanar([H | T], App) :- not(is_list(H)), aplanar(T, AppT), append([H], AppT, App). 

Ejercicio 08

%Definir los siguientes predicados: %i. ordenada(+L), que ser´a cierta si los elementos de L est´an ordenados en forma ascendente.

ordenada([]). 
ordenada([_]). 
ordenada([X, Y | XS]) :- X =< Y, ordenada([Y | XS]). 

%ii. quicksort(+L, -L1), donde L1 es el resultado de ordenar L por el m´etodo de quicksort, que %consiste en dividir a L en 2 sublistas con los menores y mayores al primer elemento, ordenar cada %una de ellas y luego proceder a concatenarlas.

quicksort_partir([], _, [], []). 
quicksort_partir([H | T], E, [H | Menores], Mayores) :- (H =< E), quicksort_partir(T, E, Menores, Mayores). 
quicksort_partir([H | T], E, Menores, [H | Mayores]) :- H > E, quicksort_partir(T, E, Menores, Mayores). 
quicksort([], []). 
quicksort([H | T], S) :- quicksort_partir(T, H, Menores, Mayores), quicksort(Menores, MenOrd), 
quicksort(Mayores, MayOrd), append(MenOrd, [H | MayOrd], S). 

%iii. inssort(+L, -L1), donde L1 es el resultado de ordenar L por el m´etodo de inserci´on, que %consiste en insertar cada elemento en el lugar adecuado del resto de la lista ya ordenada.

insertar_ordenado([], E, [E]). 
insertar_ordenado([H | T], E, [E, H | T]) :- E =< H. 
insertar_ordenado([H | T], E, [H | S]) :- E > H, insertar_ordenado(T, E, S). 
inssort([], []). 
inssort([H | T], S) :- inssort(T, SortT), insertar_ordenado(SortT, H, S). 

% Ejercicio 9 % Definir un predicado rotar(+L, +N, -R), tal que R sea la lista L rotada N posiciones (la rotaci´on se % debe hacer hacia la derecha si N>0 y hacia la izquierda si N<0). % Ejemplos: % rotar([1, a, 2, b, 3], 3, X) debe dar como respuesta X = [2, b, 3, 1, a] % rotar([1, a, 2, b, 3], -3, X) debe dar como respuesta X = [b, 3, 1, a, 2]

modulus(N, Modulus, Result) :- Result is ((N mod Modulus) + Modulus) mod Modulus. 
rotar(L, N, R) :- length(L, Length), modulus(N, Length, Rotate), append(Init, Tail, L), 
length(Tail, Rotate), append(Tail, Init, R). 

Ejercicio 10

% Definir un predicado que reciba una lista de n´umeros naturales y devuelva otra lista de n´umeros % naturales, en la que cada n´umero n de la primera lista aparezca repetido n veces en forma consecutiva, % respetando su orden de aparici´on. Considerar que la lista original siempre est´a instanciada. % Ejemplo: para la lista [2, 3, 1, 0, 2] la salida es [2, 2, 3, 3, 3, 1, 2, 2].

repetir_n(_, 0, []). 
repetir_n(E, Times, [E | T]) :- Times > 0, TimesMenos1 is Times - 1, repetir_n(E, TimesMenos1, T). 
repetir_numeros([], []). 
repetir_numeros([H | T], Reps) :- repetir_n(H, H, Hs), repetir_numeros(T, Ts), append(Hs, Ts, Reps). 

Ejercicio 11

% Escribir en Prolog un predicado que devuelva la mediana de una lista (la mediana es el elemento que % se halla en la posici´on del medio de dicha lista, tras ser ordenada). Utilizar los predicados definidos % anteriormente. Considerar que la lista siempre est´a instanciada.

mediana(L, M) :- quicksort(L, S), length(L, Length), Mitad is Length // 2, 
append(Primeros, [M | _], S), length(Primeros, Mitad). 

Ejercicio 12

% Escribir en Prolog los siguientes predicados:

% interseccion(+X, +Y, -Z), tal que Z es la intersecci´on sin repeticiones de las listas X e Y, % % respetando en Z el orden en que aparecen los elementos en X.

interseccion_con_duplicados([], _, []). 
interseccion_con_duplicados([H | T], Y, [H | IntTY]) :- pertenece(H, Y), interseccion_con_duplicados(T, Y, IntTY). 
interseccion_con_duplicados([H | T], Y, IntTY) :- not(pertenece(H, Y)), interseccion_con_duplicados(T, Y, IntTY). 
interseccion(X, Y, Z) :- interseccion_con_duplicados(X, Y, W), sacarDuplicados(W, Z). 


% data Arbol = nil | bin(Arbol, Raiz, Arbol)

Ejercicio 13

% Un ´arbol binario se representar´a en Prolog con: % nil, si es vac´io. % bin(sai, v, sad), donde v es el valor del nodo, sai es el sub´arbol izquierdo y sad es el sub´arbol % derecho. % i. Definir predicados en Prolog para las operaciones comunes de ´arboles: vacio, raiz, altura y % cantidadNodos. Asumir siempre que el ´arbol est´a instanciado.

max(X, Y, X) :- X >= Y. 
max(X, Y, Y) :- X < Y. 
min(X, Y, X) :- X < Y. 
min(X, Y, Y) :- X >= Y. 

%vacio(+Arbol).

vacio(nil). 

%raiz(+Arbol, -Raiz).

raiz(bin(_, Raiz, _), Raiz). 

%altura(+Arbol, -Altura).

altura(nil, 0). 
altura(bin(Izq, _, Der), N) :- altura(Izq, AlturaI), altura(Der, AlturaD), 
max(AlturaI, AlturaD, N). 

%cantidadNodos(+Arbol, -Cantidad).

cantidadNodos(nil, 0). 
cantidadNodos(bin(Izq, _, Der), N) :- cantidadNodos(Izq, CantI), cantidadNodos(Der, CantD), 
N is CantI + CantD + 1. 

% ii. Se define la profundidad de un nodo como la distancia desde la ra´iz hasta el mismo (la ra´iz % tiene profundidad 0). Definir un predicado hpp que permita, dado un ´arbol binario instanciado, % obtener la lista de todos los valores de las hojas que tengan profundidad par. Puede ocurrir que % dos o m´as hojas distintas tengan el mismo valor, pero en la respuesta de hpp los valores no deben % repetirse. % Ejemplo: % hpp( bin(bin(nil, 2, nil), 2, bin(bin(nil, 4, nil), 1, nil) ), L). % L = [4]; % No.

%hpp(+Arbol, -L)

hpp_con_duplicados(nil, 0, []). 
hpp_con_duplicados(nil, 1, []). 
hpp_con_duplicados(bin(Izq, Root, Der), 0, [Root | Res]) :- hpp_con_duplicados(Izq, 1, ResI), hpp_con_duplicados(Der, 1, ResD), 
append(ResI, ResD, Res). 
hpp_con_duplicados(bin(Izq, _, Der), 1, Res) :- hpp_con_duplicados(Izq, 0, ResI), hpp_con_duplicados(Der, 0, ResD), 
append(ResI, ResD, Res). 

% iv. sacarDuplicados(+L1, -L2), que saca todos los elementos duplicados de la lista L1.

pertenece(E, L1) :- append(Principio, _, L1), append(_, [E], Principio). 
sacarDuplicados([], []). 
sacarDuplicados([H | T], [H | SinDups]) :- borrar(T, H, BorrarH), sacarDuplicados(BorrarH, SinDups). 
sacarDuplicados([H | T], SinDups) :- pertenece(H, T), sacarDuplicados(T, SinDups). 
hpp(Arbol, Res) :- hpp_con_duplicados(Arbol, 0, Dups), append([_], L, Dups), sacarDuplicados(L, Res). 


Ejercicio 14

% Definir los siguientes predicados, utilizando la misma representaci´on de ´arbol binario definida en el % ejercicio 13: % i. aBB(+T) que ser´a verdadero si T es un ´arbol binario de b´usqueda.

maximo_vs(nil, N, N). 
maximo_vs(bin(Izq, Root, Der), N, Max) :- maximo_vs(Izq, Root, MaxI), maximo_vs(Der, N, MaxD), 
max(MaxI, MaxD, Max). 
minimo_vs(nil, N, N). 
minimo_vs(bin(Izq, Root, Der), N, Min) :- minimo_vs(Izq, Root, MinI), minimo_vs(Der, N, MinD), 
min(MinI, MinD, Min). 
aBB(nil). 
aBB(bin(Izq, Root, Der)) :- aBB(Izq), aBB(Der), maximo_vs(Izq, Root, Root), 
minimo_vs(Der, Root + 1, Root + 1). 

% ii. aBBInsertar(+X, +T1, -T2) donde T2 resulta de insertar X en orden en el ´arbol T1.

aBBInsertar(X, nil, bin(nil, X, nil)). 
aBBInsertar(X, bin(Izq, Root, Der), bin(NuevoIzq, Root, Der)) :- X =< Root, aBBInsertar(X, Izq, NuevoIzq). 
aBBInsertar(X, bin(Izq, Root, Der), bin(Izq, Root, NuevoDer)) :- X > Root, aBBInsertar(X, Der, NuevoDer). 


Ejercicio 15

% Un ´arbol n-ario de naturales se representar´a en Prolog con: % hoja(V), donde V es un natural seg´un la representaci´øn de Prolog. % nodo(V, Hijos), donde V es un natural seg´un la representaci´øn de Prolog, e Hijos es una lista % no vac´ia de ´arboles n-arios de naturales. % Definir el predicado mayores(+Arbol, +Max) que dado un ´arbol n-ario de naturales (que podr´ia % contener variables en los nodos) devuelve verdadero si: % Los naturales que contiene el ´arbol son menores o iguales a Max (en caso de ser variables, deber´an % instanciarse con valores en dicho rango). % El valor de cada nodo del ´arbol es mayor que la suma de los valores de sus hijos. % ejemplo: mayores(nodo(X, [hoja(0), nodo(1,[hoja(0), hoja(0)]),nodo(4,[hoja(1), hoja(0), nodo(1, [hoja(0)])])]),9)

%in_range(+Min, +Max, -Num).

in_range(Min, Max, Min) :- Min =< Max. 
in_range(Min, Max, N) :- Min =< Max, NextMin is Min + 1, in_range(NextMin, Max, N). 
valor(hoja(V), V). 
valor(nodo(V, _), V). 
mayores(hoja(V), Max) :- in_range(0, Max, V). 
mayores(nodo(V, [X]), Max) :- valor(X, Val), in_range(0, Max, Val), Val1 is Val + 1, in_range(Val1, Max, V). 
mayores(nodo(V, [X, Y | T]), Max) :- valor(X, Val), in_range(0, Max, Val), Val1 is Val + 1, in_range(Val1, Max, V), 
VMenosX is V - Val, mayores(nodo(VMenosX, [Y | T]), Max). 

%mayores no anda bien, no hace la suma de todos los subhijos, sino de los inmediatos... como se hace bien? facilmente?

Ejercicio 16

% Definir el predicado combinador(+L,+D,+H,-XS), que debe dar verdadero cuando XS es una lista de % naturales de longitud L, y cada uno de sus elementos XSi cumple que D ? XSi ? H. No se deben devolver % soluciones repetidas. % Por ejemplo: combinador(2,3,5,X). % X = [3,3] ; % X = [3,4] ; % X = [3,5] ; % X = [4,3] ; % X = [4,4] ; % X = [4,5] ; % X = [5,3] ; % X = [5,4] ; % X = [5,5] ;

%in_range(+Min, +Max, -Min).

in_range(Min, Max, Min) :- Min =< Max. 
in_range(Min, Max, N) :- Min =< Max, NextMin is Min + 1, in_range(NextMin, Max, N). 

%combinador(+L, +D, +H, -XS).

combinador(0, _, _, []). 
combinador(L, Min, Max, [H | T]) :- L > 0, in_range(Min, Max, H), L1 is L - 1, combinador(L1, Min, Max, T). 

Ejercicio 17

% Un cuadrado semi-latino es una matriz cuadrada de naturales (incluido el cero) donde todas las filas % de la matriz suman lo mismo. Por ejemplo: % 1 3 0 % 2 2 0 todas las filas suman 4 % 1 1 2 % Representamos la matriz como una lista de filas, donde cada fila es una lista de naturales. El ejemplo % anterior se representar´ia de la siguiente manera: [[1,3,0],[2,2,0],[1,1,2]]. % Se pide definir el predicado cuadradoSemiLatino(N,XS). El par´ametro N debe estar instanciado, y % XS no puede estar instanciado. El predicado debe ir devolviendo matrices (utilizando la representaci % ´on antes mencionada), que sean cuadrados semi-latinos de dimensi´on N*N. Dichas matrices deben % devolverse de manera ordenada: primero aqu´ellas cuyas filas suman 0, luego 1, luego 2, etc.. % Ejemplo: cuadradoSemiLatino(2,X). devuelve: % X = [[0, 0], [0, 0]] ; % X = [[0, 1], [0, 1]] ; % X = [[0, 1], [1, 0]] ; % X = [[1, 0], [0, 1]] ; % X = [[1, 0], [1, 0]] ; % X = [[0, 2], [0, 2]] ; % etc. % Para la implementaci´on de cuadradoSemiLatino se cuenta con el siguiente predicado: % desde(D, D). % desde(D, X) :- DD is D+1, desde(DD, X).

%desde(+Desde, -Numero).

desde(D, D). 
desde(D, X) :- DD is D+1, desde(DD, X). 

%lista_semi_latina(+Longuitud, +Suma, -Lista).

lista_semi_latina(0, 0, []). 
lista_semi_latina(Long, Suma, [H | T]) :- Long > 0, Suma >= 0, Long1 is Long - 1, in_range(0, Suma, H), 
NuevaSuma is Suma - H, lista_semi_latina(Long1, NuevaSuma, T). 

%rectanguloSemiLatino(+Columnas, +Filas, +Suma, -XS).

rectanguloSemiLatino(_, 0, Suma, []) :- Suma >= 0. 
rectanguloSemiLatino(Columnas, Filas, Suma, [H | T]) :- Filas > 0, Filas1 is Filas - 1, lista_semi_latina(Columnas, Suma, H), 
rectanguloSemiLatino(Columnas, Filas1, Suma, T). 

%cuadradoSemiLatino(+N, -XS).

cuadradoSemiLatino(N, X) :- desde(0, Suma), rectanguloSemiLatino(N, N, Suma, X). 

Ejercicio 18

% Sea la estructura Agenda, y los siguientes predicados disponibles: % personas(+Agenda, -Personas), que tiene ´exito cuando Personas contiene toda la lista % personas de la Agenda. % edad(+Agenda, +Persona, -Edad), que tiene ´exito cuando la Persona tiene edad Edad % la Agenda. % Definir el predicado personasEnPromedio(+Agenda, +Edad, -Conjunto) que tenga ´exito cuando % Conjunto sea una lista de Personas de la Agenda, cuyo promedio de edad sea menor a Edad.

%personas(+Agenda, -Personas).

personas(agenda(Personas), Personas). 

%edad(+Agenda, +Persona, -Edad).

edad(agenda([persona(Nombre, Edad) | _]), Nombre, Edad). 
edad(agenda([persona(OtroNombre, Edad) | Resto]), Nombre, Edad) :- OtroNombre \= Nombre, 
edad(agenda(Resto), Nombre, Edad). 
subconjuntos_personas(agenda([]), []). 
subconjuntos_personas(agenda([H | T]), [H | Sub]) :- subconjuntos_personas(agenda(T), Sub). 
subconjuntos_personas(agenda([_ | T]), Sub) :- subconjuntos_personas(agenda(T), Sub). 

%promedio_edades(Personas, Edad).

suma_edades([persona(_, Edad)], Edad). 
suma_edades([persona(_, Edad) | T], Suma) :- suma_edades(T, SumaT), Suma is SumaT + Edad. 

%personasEnPromedio(+Agenda, +Edad, -Conjunto).

personasEnPromedio(Agenda, Edad, Conjunto) :- subconjuntos_personas(Agenda, Conjunto), suma_edades(Conjunto, Suma), 
length(Conjunto, Cantidad), Promedio is (Suma // Cantidad), Edad > Promedio. 

%caso: personasEnPromedio(agenda([persona(0, 0), persona(0, 1), persona(0, 2), persona(0, 3), persona(0, 4), persona(0, 5)]), 0, X).

Ejercicio 19

% (opcional) % Torres de Hanoi. Se tienen tres estacas A, B y C, y N discos de distintos tama˜nos, perforados en el % centro. Los discos pueden apilarse en las estacas formando torres, y est´an ubicados inicialmente en % la estaca A en orden decreciente de tama˜no. El problema consiste en mover los discos de A a C de % tal manera que terminen ordenados como lo estaban originalmente. La tarea debe efectuarse bajo las % siguientes restricciones: % En cada paso s´olo un disco puede moverse de una estaca a otra. % Nunca puede ubicarse un disco sobre otro m´as peque˜no. % Usando Prolog, modelar y resolver el problema de las torres de Hanoi para tres estacas y N discos. % data Estacas = a | b | c % data Movimiento = Mover Estacas Estacas

%es_estaca(+E).

es_estaca(a). 
es_estaca(b). 
es_estaca(c). 

%estacas_diferentes(-E1, -E2, -E3).

estacas_diferentes(a, b, c). 
estacas_diferentes(a, c, b). 
estacas_diferentes(b, a, c). 
estacas_diferentes(b, c, a). 
estacas_diferentes(c, a, b). 
estacas_diferentes(c, b, a). 

%hanoi_mover(+N, +Desde, +Hasta, -Movimientos).

hanoi_mover(0, Desde, Hasta, []) :- es_estaca(Desde), es_estaca(Hasta). 
hanoi_mover(N, Desde, Hasta, Movimientos) :- N > 0, N1 is N - 1, estacas_diferentes(Desde, Hasta, Otra), 
hanoi_mover(N1, Desde, Otra, MovsDesdeOtra), 
hanoi_mover(N1, Otra, Hasta, MovsOtraHasta), 
append(MovsDesdeOtra, [mov(Desde, Hasta) | MovsOtraHasta], Movimientos). 

%hanoi(+N, -Movimientos).

hanoi(N, Movimientos) :- hanoi_mover(N, a, c, Movimientos). 

Funciones Varias

%repeat(-Elemento, -Lista). % Requiere: true. % Asegura: Lista es una lista que contiene solamente a Elem (cero o mas veces).

repeat(_, []). 
repeat(Elem, [Elem | Tail]) :- repeat(Elem, Tail). 

%multi_length(-Lista_de_Listas, -Lista_de_Longuitudes). % Requiere: Lista_de_Listas es una lista de listas, y Lista_de_Longuitudes es una lista de naturales. % Asegura: Lista_de_Longuitudes es una lista que contiene las longuitudes de los elementos de Lista_de_Listas.

multi_length([], []). 
multi_length([X | XS], [L | LS]) :- length(X, L), multi_length(XS, LS). 

%multi_append(-Lista_de_Listas, -Listas_Unidas). % Requiere: Lista_de_Listas no contiene ninguna lista vacia, pero ella si puede ser la lista vacia. % Asegura: Listas_Unidas son todas las listas de la listas unidas, % en el orden en que aparecian en la lista de listas.

multi_append([], []). 
multi_append([[X] | YS], [X | ZS]) :- multi_append(YS, ZS). 
multi_append([[X1, X2 | XS] | YS], [X1 | ZS]) :- multi_append([[X2 | XS] | YS], ZS). 

%particion_doble(-Parte1, -Parte2, -Lista). % Requiere: true. % Asegura: Parte1 y Parte2 son una particion de Lista en dos listas, % preservando en ellas el orden relativo original de los elementos.

particion_doble([], [], []). 
particion_doble([X | XS], [], [X | XS]). 
particion_doble([], [Y | YS], [Y | YS]). 
particion_doble([X | XS], [Y | YS], [X | ZS]) :- particion_doble(XS, [Y | YS], ZS). 
particion_doble([X | XS], [Y | YS], [Y | ZS]) :- particion_doble([X | XS], YS, ZS). 

%particion_doble_sin_vacio(-Parte1, -Parte2, -Lista). % Requiere: true. % Asegura: Parte1 y Parte2 son una particion de Lista en dos listas (ninguna vacia), % preservando en ellas el orden relativo original de los elementos.

particion_doble_sin_vacio([X], [Y | YS], [X, Y | YS]). 
particion_doble_sin_vacio([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_sin_vacio([X2 | XS], [Y | YS], ZS). 
particion_doble_sin_vacio([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_sin_vacio([Y | YS], [X2 | XS], ZS). 

%particion(-ListaDeSublistas, +Lista). % Requiere: Lista es una Lista, ListaDeSublistas una lista de listas. % Asegura: ListaDeSublistas es una lista de sublistas disjuntas que forman Lista.

particion([], []). 
particion( XS, [X | XS]). 
particion([[X | XS], Y | YS], ZS) :- particion_doble_sin_vacio([X | XS], PS, ZS). 


%particion_de_longuitud_n(+Lista, +Longuitud, -ListaDeSublistas) % Requiere: Lista es una Lista de longuitud multiplo de Longuitud, ListaDeSublistas una lista de listas. % Asegura: ListaDeSublistas es una lista de sublistas disjuntas que forman Lista cada una de longuitud Longuitud.

particion_de_longuitud_n(Lista, Longuitud, ListaDeSublistas) :- particion(ListaDeSublistas, Lista), 
length(Lista, Length_Lista), Cantidad is Length_Lista // Longuitud, 
repeat(Longuitud, Lista_Longs), length(Lista_Longs, Cantidad), 
multi_length(ListaDeSublistas, Lista_Longs). 

%lista_de_grupos(+Lista_de_Paises_en_Grupos, +Ids, -Grupos).

lista_de_grupos([], [], []). 
lista_de_grupos([P | PS], [I | IS], [grupo(I, P) | GS]) :- lista_de_grupos(PS, IS, GS). 

% Requiere: length(Lista_de_Paises_en_Grupos) == length(Ids). % Asegura: Grupos es la formacion de grupos asignando un id a cada grupo de paises de la lista.

%mesclar_particiones_de_listas(-Particiones, +Listas_de_Listas).

grupos(Ps, Ids, Grupos) :- lista_de_grupos(Lista_de_Paises_en_Grupos, Ids, Grupos). 

%grupos(+Ps, +Ids, -Grupos)

grupos(Ps, Ids, Grupos) :- lista_de_grupos(Lista_de_Paises_en_Grupos, Ids, Grupos). 
paises([[argentina, brasil], [mejico,canada], 
[sudafrica, egipto]]). 
listas([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]). 
listas2([1, 2, 3]). 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Funciones de Numeros - Start % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%es_natural(-Numero).

es_natural(0). 
es_natural(N) :- es_natural(N1), N is N1 + 1. 

%es_positivo(-Numero).

es_positivo(1). 
es_positivo(N) :- es_natural(N1), N is N1 + 1. 

%es_negativo(-Numero).

es_negativo(-1). 
es_negativo(N) :- es_negativo(N1), N is N1 - 1. 

%diferencia_con_siguiente_entero(-Signo, +Numero).

diferencia_con_siguiente_entero(1, 0). 
diferencia_con_siguiente_entero(1, N) :- N > 0. 
diferencia_con_siguiente_entero(0, N) :- N < 0. 

%es_entero(-Signo, +Numero).

es_entero(0). 
es_entero(N) :- es_entero(M), NM is -M, diferencia_con_siguiente_entero(S, NM), 
N is NM + S. 

%signo_aux(-Signo, +Numero).

signo_aux(0, 0). 
signo_aux(1, N) :- N > 0. 
signo_aux(-1, N) :- N < 0. 

%signo(-Signo, -Numero).

signo(0, 0). 
signo(S, N) :- es_entero(N), N \= 0, signo_aux(S, N). 

%en_rango(-Numero, +Desde, +Hasta).

en_rango(D, D, H) :- D =< H. 
en_rango(N, D, H) :- D =< H, ND is D + 1, en_rango(N, ND, H). 

%desde(-Numero, +Desde).

desde(D, D). 
desde(N, D) :- DD is D+1, desde(N, DD). 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Funciones de Numeros - End % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Funciones de Arboles - Start % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%es_arbol_de_altura(-Arbol, +Altura).

es_arbol_de_altura(nil, 0). 
es_arbol_de_altura(bin(I, _, D), H) :- H > 0, H1 is H - 1, 
en_rango(HI, 0, H1), 
en_rango(HD, 0, H1), H1 is max(HD, HI), 
es_arbol_de_altura(I, HI), es_arbol_de_altura(D, HD). 

%altura(-Arbol, -Altura).

altura(A, H) :- es_natural(H), es_arbol_de_altura(A, H). 

%preorder_de_arboles(-Nodos, -Arbol).

preorder_de_arboles([], []). 
preorder_de_arboles(L, [nil | AS]) :- preorder_de_arboles(L, AS). 
preorder_de_arboles([X | XS], [bin(I, X, D) | AS]) :- preorder_de_arboles(XS, [I, D | AS]). 

%preorder(-Nodos, -Arbol).

preorder(L, A) :- preorder_de_arboles(L, [A]). 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Funciones de Arboles - End % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Funciones de Listas - Comienzo % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% map_tomar_uno_de_lista(-Reordenado, -Resto, +ListaDeListas) % Requiere: true. % Asegura: Reordenado es una lista formada agarrando un elemento de cada sublista % de ListaDeListas y Resto es lo que queda despues de sacar eso. % Uso:

map_tomar_uno_de_lista([], [], []). 
map_tomar_uno_de_lista([H | T], [R | RS], [L | LS]) :- particion_doble_unicas_vacia([H], R, L), 
map_tomar_uno_de_lista(T, RS, LS). 

% particion(-ListaDeSublistas, +Lista). % Requiere: true. % Asegura: ListaDeSublistas es una lista de sublistas disjuntas que forman Lista. % particion( XS, [X | XS]). % particion([[X | XS], Y | YS], ZS) :- particion_doble_unicas([X | XS], WS, ZS), particion(Y | YS, WS).

% particion_doble_unicas(-Parte1, -Parte2, -Lista). % Requiere: true. % Asegura: Parte1 y Parte2 son una particion de Lista en dos listas (ninguna vacia), % preservando en ellas el orden relativo original de los elementos.

particion_doble_unicas([X], [Y | YS], [X, Y | YS]). 
particion_doble_unicas([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_unicas([X2 | XS], [Y | YS], ZS). 
particion_doble_unicas([X1, X2 | XS], [Y | YS], [X1 | ZS]) :- particion_doble_unicas([Y | YS], [X2 | XS], ZS). 

% particiones_de_longuitud_n(-ListaDeSublistas, +Longuitud, +Lista) % Requiere: true. % Asegura: ListaDeSublistas es una lista de sublistas disjuntas que forman Lista cada una de longuitud Longuitud.

particiones_de_longuitud_n([XS], L, XS) :- length(XS, L). 
particiones_de_longuitud_n([X | XS], L, ZS) :- not(length(ZS, L)), particion_doble_unicas(X, YS, ZS), length(X, L), 
particiones_de_longuitud_n(XS, L, YS). 

% map_particiones_de_longuitud_n(-Sublistas, +CantidadDeGrupos, +Listas) % Requiere: true. % Asegura: similar a Haskell: map particiones_de_longuitud_n.

map_particiones_de_longuitud_n([], N, []) :- N > 0. 
map_particiones_de_longuitud_n([X | XS], N, [Y | YS]) :- map_particiones_de_longuitud_n(XS, N, YS), 
particiones_de_longuitud_n(X, N, Y). 

% iesimos_elementos(-Iesimos, +Indice, -ListaDeListas) % Requiere: true. % Asegura: Iesimos son los iesimos elementos de cada lista de ListaDeListas.

iesimos_elementos([], N, []) :- N >= 0. 
iesimos_elementos([E | XS], I, [Y | YS]) :- nth0(I, Y, E), iesimos_elementos(XS, I, YS). 


% generar_listas_tomando_de_listas_entre_iesimos(-Reordenado, +Desde, +Hasta, +ListaDeListas)

generar_listas_tomando_de_listas_entre_iesimos([], D, H, L) :- D > H, is_list(L). 
generar_listas_tomando_de_listas_entre_iesimos([X | XS], D, H, YS) :- D =< H, D1 is D + 1, iesimos_elementos(X, D, YS), 
generar_listas_tomando_de_listas_entre_iesimos(XS, D1, H, YS). 

% last(+N, -Tail, -Lista). % Requiere: true. % Asegura: Tail son los ultimos n elementos de Lista.

last(N, Tail, Lista) :- length(Tail, N), append(_, Tail, Lista). 

% sin_iesimo(-ListaSinIesimo, -Indice, -Lista) % Requiere: true % Asegura: ListaSinIesimo es la lista sin el elemento en la posicion Indice de Lista.

sin_iesimo(NL, I, L) :- append(Init, [_ | Tail], L), length(Init, I), append(Init, Tail, NL). 

% sin_primera_aparicion(-ListaSinElemento, -Elemento, -Lista) % Requiere: true. % Asegura: ListaSinElemento es igual a Lista sin la primera aparicion del elemento.

sin_primera_aparicion(ZS, E, L) :- append(ZS1, [E | ZS2], L), append(ZS1, ZS2, ZS), not(member(E, ZS1)). 

% concat(-Lista_de_Listas, -Listas_Unidas). % Requiere: true. % Asegura: Listas_Unidas son todas las listas de la listas unidas, % en el orden en que aparecian en la lista de listas.

concat([], []). 
concat([[X] | YS], [X | ZS]) :- concat(YS, ZS). 
concat([[X1, X2 | XS] | YS], [X1 | ZS]) :- concat([[X2 | XS] | YS], ZS). 

% map_concat(-ListaDeListasDeListas, +ListasMappeadas) % Requiere: true. % Asegura: similar a Haskell: map concat

map_concat([], []). 
map_concat([X | XS], [Y | YS]) :- concat(X, Y), map_concat(XS, YS). 

% take(+N, -Tail, -Lista). % Requiere: true. % Asegura: Tail son los elementos que quedan luego de sacar los n primeros % elementos a Lista.

drop(N, Tail, Lista) :- length(Init, N), append(Init, Tail, Lista). 

% pertenece(-Elemento, -Lista) % Requiere: true % Asegura: Elemento pertenece a Lista.

pertenece(E, L) :- append(_, [E | _], L). 

% sin_un_elemento(-ListaSinElemento, -Elemento, -Lista) % Requiere: true. % Asegura: ListaSinElemento es igual a Lista sin una vez ese elemento.

sin_un_elemento(ZS, E, L) :- append(ZS1, [E | ZS2], L), append(ZS1, ZS2, ZS). 

% sin_elemento(-ListaSinElementos, +Elemento, +Lista) % Requiere: true. % Asegura: ListaSinElementos es igual a Lista sin todas las apariciones del elemento.

sin_elemento([], _, []). 
sin_elemento(L, H, [H | T]) :- sin_elemento(L, H, T). 
sin_elemento([H | L], E, [H | T]) :- E \= H, sin_elemento(L, E, T). 

% iesimo(-Elemento, -Indice, -Lista) % Requiere: true % Asegura: Elemento es el elemento en la posicion Indice de Lista.

iesimo(E, I, L) :- append(Init, [E | _], L), length(Init, I). 

% interseccion(-Interseccion, +ListaL, +ListaR) % Requiere: true. % Asegura: Interseccion es la interseccion sin duplicados de ListaL y ListaR % manteniendo el orden de los elementos en ListaL.

interseccion([], [], []). 
interseccion([E | ZS], [E | LL], LRE) :- member(E, LRE), delete(LRE, E, LR), 
interseccion(ZS, LL, LR). 
interseccion(ZS, [E | LL], LR) :- not(member(E, LR)), interseccion(ZS, LL, LR). 

% sin_repetidos(-ListaSinRepetidos, +Lista). % Requiere: true. % Asegura: ListaSinRepetidos es igual a Lista solo que no tiene repetidos.

sin_repetidos([], []). 
sin_repetidos([E | XS], [E | YS]) :- not(member(E, YS)), sin_repetidos(XS, YS). 
sin_repetidos(XS, [E | YS]) :- member(E, YS), sin_repetidos(XS, YS). 
sin_repetidos([E | XS], [E | YS]) :- member(E, YS), sin_repetidos(XSE, YS), 
select(E, XSE, XS). 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Funciones de Listas - Fin % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%