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 226: Línea 226:
  sacarDuplicados([H | T], SinDups) :- pertenece(H, T), sacarDuplicados(T, SinDups).  
  sacarDuplicados([H | T], SinDups) :- pertenece(H, T), sacarDuplicados(T, SinDups).  


%Ejecicio 7
==Ejercicio 05==
 
==Ejercicio 06==
 
==Ejercicio 07==
%Definir el predicado aplanar(+Xs, -Ys), que es verdadero sii Ys contiene los elementos contenidos  
%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  
%en alg´un nivel de Xs, en el mismo orden de aparici´on. Los elementos de Xs son enteros, ´atomos o  
Línea 265: Línea 269:
  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 09==
% Definir un predicado rotar(+L, +N, -R), tal que R sea la lista L rotada N posiciones (la rotaci´on se  
% 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).  
% debe hacer hacia la derecha si N>0 y hacia la izquierda si N<0).  

Revisión del 19:16 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). 

Ejercicio 05

Ejercicio 06

Ejercicio 07

%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 09

% 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 % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%