% vim: set ft=prolog:

% Usa o arquivo plunit.pl se é uma versão é < 6.0
:- current_prolog_flag(version, V), V < 60000, use_module(plunit) ; true.
% Usa o arquivo plunit.pl que vem com o Prolog se a versão é > 6.0.0
:- current_prolog_flag(version, V), V > 60000, use_module(library(plunit)) ; true.


%%%%%%%%%%%
% Exemplo 1
%
% Defina um predicado tamanho(L, T) que é verdadeiro se a quantidade de
% elementos na lista L é T.

% tamanho(+XS, ?T) is nondet
%
% Verdadeiro se a quantidade de elementos na lista XS é T.
%
% Veja o predicado pré-defininido length.

:- begin_tests(tamanho).

test(t0) :- tamanho([], 0).
test(t1) :- tamanho([1], 1).
test(t2) :- tamanho([7, 2], 2).

:- end_tests(tamanho).


tamanho([_ | XS], T) :-
	tamanho(XS, T0),
	T is T0 + 1.

tamanho([], 0).


%%%%%%%%%%%
% Exemplo 2
%
% Defina um predicado kesimo(XS, K, N) que é verdadeiro se N é o K-ésimo
% elemento da lista XS.

% kesimo(+XS, +K, ?N) is semdet
%
% Verdadeiro se N é o K-ésimo elemento da lista XS.
%
% Veja o predicado pré-definido nth0.

:- begin_tests(kesimo).

test(t0) :- kesimo([5, 3, 10], 0, 5).
test(t1) :- kesimo([5, 3, 10], 1, 3).
test(t2) :- kesimo([5, 3, 10], 2, 10).
test(t4, fail) :- kesimo([5, 3, 10], 4, _).

:- end_tests(kesimo).


kesimo([X | _], 0, X) :- !.

kesimo([_ | XS], K, X) :-
    K > 0,
    K0 is K - 1,
    kesimo(XS, K0, X).


%%%%%%%%%%%
% Exemplo 3
%
% Defina um predicado comprimida(XS, YS) que é verdadeiro a lista YS é XS
% comprimida, isto é, sem elementos repetidos consecutivos.

% comprimida(+XS, ?YS) is nondet
%
% Verdadeiro se XS comprimida é YS, isto é, sem elementos repetidos
% consecutivos.

:- begin_tests(comprimida).

test(t0) :- comprimida([], []).
test(t1) :- comprimida([x], [x]).
test(t2) :- comprimida([3, 3, 4, 4, 4, 3, 5, 5, 5], [3, 4, 3, 5]).

:- end_tests(comprimida).

comprimida([], []).

comprimida([X | XS], YS) :-
	comprimida(XS, YS),
	[X | _] = YS, !.

comprimida([X | XS], [X | YS]) :-
	comprimida(XS, YS),
	[X | _] \= YS.

% comprimida2(+XS, ?YS) is nondet
%
% Verdadeiro se XS comprimida é YS, isto é, sem elementos repetidos
% consecutivos.

:- begin_tests(comprimida2).

test(t0) :- comprimida2([], []).
test(t1) :- comprimida2([x], [x]).
test(t2) :- comprimida2([3, 3, 4, 4, 4, 3, 5, 5, 5], [3, 4, 3, 5]).

:- end_tests(comprimida2).

comprimida2([], []).

comprimida2([X], [X]) :- !.

comprimida2([X, X | XS], YS) :-
	comprimida2([X | XS], YS), !.

comprimida2([X, Y | XS], [X | YS]) :-
	X \= Y,
	comprimida2([Y | XS], YS).

%%%%%%%%%%%
% Exemplo 4
%
% membro(?X, ?XS) is nondet
%
% Verdadeiro se X é um elemento de XS.

:- begin_tests(membro).

test(t0, [nondet]) :- membro(1, [1, 3, 7]).
test(t1, [nondet]) :- membro(3, [1, 3, 7]).
test(t2, [nondet]) :- membro(7, [1, 3, 7]).
test(t3, all(X == [1, 3, 7, -2])) :- membro(X, [1, 3, 7, -2]).

:- end_tests(membro).

membro(X, [X | _]).
membro(X, [_ | XS]) :-
    membro(X, XS).


% membrochk(+X, ?XS) is semidet
%
% Verdadeiro se X é um elemento de XS.

:- begin_tests(membrochk).

test(t0) :- membrochk(1, [1, 3, 7]).
test(t1) :- membrochk(7, [1, 3, 7]).
test(t2, X == 1) :- membrochk(X, [1, 3, 7]).
test(t3, [fail]) :- membrochk(5, [1, 3, 7]).

:- end_tests(membrochk).

membrochk(X, [X | _]) :- !.
membrochk(X, [_ | XS]) :-
    membrochk(X, XS).


%%%%%%%%%%%
% Exemplo 5
%
% concatena(?X, ?Y, ?Z) is nondet
%
% Verdadeiro se Z é Y concatenado com Z.

:- begin_tests(concatena).

test(t0) :- concatena([1, 2], [3, 4, 5], [1, 2, 3, 4, 5]).
test(t1, [nondet, XS == [1, 2, 4]]) :- concatena(XS, [3], [1, 2, 4, 3]).
test(t2, YS == [4, 3]) :- concatena([1, 2], YS, [1, 2, 4, 3]).
test(t3, all(p(XS, YS) == [
         p([], [1, 2, 3]),
         p([1], [2, 3]),
         p([1, 2], [3]),
         p([1, 2, 3], [])])) :-
    concatena(XS, YS, [1, 2, 3]).


:- end_tests(concatena).

concatena([], YS, YS).

concatena([X | XS], YS, [X | XSYS]) :-
    concatena(XS, YS, XSYS).


%%%%%%%%%%%
% Exemplo 6
%
% super_soma(XS, S) is semidet
%
% Verdadeiro se S e a soma de todos elementos da lista aninhada XS.

:- begin_tests(super_soma).

test(t0) :- super_soma([[], [], [[], []]], 0).
test(t1) :- super_soma([[1], [2, 3], [4, [5, 6], 7]], 28).
test(t2, S == 36) :- super_soma([[1, 2], 3, [4, [5, 6, [7]], 8]], S).

:- end_tests(super_soma).

super_soma([], 0).

super_soma([X | XS], S) :-
    \+ is_list(X), !,
    super_soma(XS, S1),
    S is X + S1.

super_soma([X | XS], S) :-
    super_soma(X, S1),
    super_soma(XS, S2),
    S is S1 + S2.
