% vim: set ft=prolog:

%% Ex 7 %%
%% triangulo(+A, +B, +C, ?T) is nondet
%
%  Verdadeiro se A, B e C formam um triângulo do tipo T.
%  Exemplos
%  ?- triangulo(3, 3, 3, T).
%  T = equilatero ;
%  T = isosceles ;
%  T = isosceles ;
%  T = isosceles ;
%  false.
%  ?- triangulo(2, 3, 3, T).
%  T = isosceles ;
%  false.
%  ?- triangulo(3, 4, 5, T).
%  T = escaleno ;
%  false.

triangulo(A, B, C, equilatero) :-
    triangulo(A, B, C),
    A =:= B,
    B =:= C.

triangulo(A, B, C, isosceles) :-
    triangulo(A, B, C),
    (   A =:= B
    ;   A =:= C
    ;   B =:= C
    ).

triangulo(A, B, C, escaleno) :-
    triangulo(A, B, C),
    A =\= B,
    A =\= C,
    B =\= C.

%% triangulo(+A, +B, +C) is semidet
%  
%  Verdadeiro se se A, B e C formam um triângulo.
%  Exemplos
%  ?- triangulo(3, 4, 5).
%  true.
%  ?- triangulo(2, 4, 7).
%  false.

triangulo(A, B, C) :-
    A > 0,
    B > 0,
    C > 0,
    A + B > C,
    A + C > B,
    B + C > A.

%% Ex 8 %%
%% area(+F, ?A) is semidet
%
%  Verdadeiro se a figura F tem área A.
%  Exemplos
%  ?- area(circulo(2), A).
%  A = 12.566370614359172).
%  ?- area(quadrado(4), A).
%  A = 16.
%  ?- area(retangulo(3, 4), A).
%  A = 12.

area(circulo(R), A) :-
    A is pi * R * R.

area(quadrado(L), A) :-
    A is L * L.

area(retangulo(H, L), A) :-
    A is H * L.

%% Ex 9 %%
%% soma_quadrado_maiores(+A, +B, +C, ?S)
%  
%  Verdadeiro se S é a soma dos quadrados dos dois maiores números entre
%  A, B e C.
%  Exemplos
%  ?- soma_quadrado_maiores(3, 4, 5, S).
%  S = 41.
%  ?- soma_quadrado_maiores(4, 3, 5, S).
%  S = 41.

soma_quadrado_maiores(A, B, C, S) :-
    A >= B, !,
    maximo(B, C, X),
    soma_quadrado(A, X, S).

soma_quadrado_maiores(A, B, C, S) :-
    B > A,
    maximo(A, C, X),
    soma_quadrado(B, X, S).

soma_quadrado(A, B, S) :-
    S is A * A + B * B.

%% maximo(+A, +B, ?C) is semidet
%  
%  Verdadeiro se C é o valor máximo entre A e B.
%  Exemplos
%  ?- maximo(3, 5, C).
%  C = 5.
%  ?- maximo(7, 4, C).
%  C = 7.

maximo(A, B, A) :-
    A >= B, !.

maximo(A, B, B) :-
    B > A.

%% Ex 10 %%
%% palindromo(+X) is semidet
%
%  Verdadeiro se X é um número palíndromo.
%  Exemplos
%  ?- palindromo(8).
%  true.
%  ?- palindromo(7227).
%  true.
%  ?- palindromo(72027).
%  true.
%  ?- palindromo(12).
%  false.
%  ?- palindromo(347).
%  false

palindromo(X) :-
    reverso(X, 0, R),
    X =:= R, !.

reverso(0, S, S).
reverso(X0, S0, R) :-
    X0 > 0,
    S1 is S0 * 10 + X0 rem 10,
    X1 is X0 div 10,
    reverso(X1, S1, R).

%% Ex 13 %%
%% primo(+X)
%  
%  Verdadeiro se X é um número primo.
%  ?- primo(2).
%  true.
%  ?- primo(3).
%  true.
%  ?- primo(5).
%  true.
%  ?- primo(7).
%  true.
%  ?- primo(19).
%  true.
%  ?- primo(4).
%  false.
%  ?- primo(6).
%  false.
%  ?- primo(8).
%  false.
%  ?- primo(9).
%  false.

primo(X) :-
    menor_divisor(X, 2, Y),
    X =:= Y.

% X é o menor divisor de X començando com X
menor_divisor(X, X, X) :- !.

% D é o menor divisor de X començando com D se X é divisível por D.
menor_divisor(X, D, D) :-
    divisivel(X, D), !.

menor_divisor(X, D, Y) :-
    \+ divisivel(X, D),
    D1 is D + 1,
    menor_divisor(X, D1, Y).

divisivel(X, Y) :-
    X rem Y =:= 0.

%% Ex 15 %%
%% perfeito(+X) is semidet
%
%  Verdadeiro se X é um número perfeito.
%  ?- perfeito(6).
%  true.
%  ?- perfeito(28).
%  true.
%  ?- perfeito(496).
%  true.
%  ?- perfeito(5).
%  false.
%  ?- perfeito(7).
%  false.
%  ?- perfeito(27).
%  false.
%  ?- perfeito(29).
%  false

perfeito(X) :-
    soma_divisores(X, S),
    X =:= S.

soma_divisores(X, S) :-
    soma_divisores(X, 1, 0, S).
    
soma_divisores(X, D, S, S) :-
    D >= X, !.

soma_divisores(X, D, S0, S) :-
    divisivel(X, D), !,
    S1 is S0 + D,
    D1 is D + 1,
    soma_divisores(X, D1, S1, S).

soma_divisores(X, D, S0, S) :-
    \+ divisivel(X, D),
    D1 is D + 1,
    soma_divisores(X, D1, S0, S).
