% -*- prolog -*-

% nub (odstranění duplikátů ze zeznamu)
oOA( [], [] ).
oOA( [H|T], [H|S] ) :- delete( T, H, X ), oOA( X, S ).


nd35(X) :- X rem 5 =\= 0, X rem 3 =\= 0.

max( X, Y, Z ) :- X =< Y, !, Z = Y.
max( X, _Y, X ). % :- X > Y.

min( X, Y, Z ) :- X >= Y, !, Z = Y.
mix( X, _Y, X ). 

gcd( A, 0, A ) :- !.
gcd( A, B, GCD ) :-
    MOD is A rem B,
    gcd( B, MOD, GCD ).


% uspeje tolikrat kolik je vyskytu prvku v seznamu
% obousměrný 
% mem1( a, [A,B]) ~> A = a; B = a
% mem1( X, [a,b]) ~> X = a; X = b
mem1( H, [H|_] ).
mem1( H, [_|T] ) :- mem1( H, T ).

% uspěje nejvýše jednou
% obousměrný ale s unifikací jen 1. proměnné/prvku
% mem2( a, [A,B] ) ~> A = a.
% mem2( X, [a,b] ) ~> X = a.
mem2( H, [H|_] ) :- !.
mem2( H, [_|T] ) :- mem2( H, T ).

% jednosměrný (bez substituce volných proměnných), uspěje nejvýše jednou
% mem3( a, [X, Y, Z]) ~> fail.
mem3( H, [K|_] ) :- H == K. % identita, bez substituce
mem3( H, [K|T] ) :- H \== K, mem3( H, T ).


% trojice různých prvků seznamu, v libovolném pořadí
threeMems( List, A, B, C ) :-
    member( A, List ),
    member( B, List ),
    A \= B,
    member( C, List ),
    A \= C, B \= C.

variace3( List, Y ) :-
    findall( [A,B,C], threeMems( List, A, B, C ), Y ).

% variace3( [1,2,2], Y ). ~> fail

% trojice prvků seznamu z různých pozic
threeMemsFix( List, A, B, C ) :-
    nth0( I1, List, A ),
    nth0( I2, List, B ),
    I1 \= I2,
    nth0( I3, List, C ),
    I1 \= I3, I2 \= I3.

% resi problem kdy se seznamu opakuji prvky ale v kombinacich ne
variace3_( List, Y ) :-
    findall( [A,B,C], threeMemsFix( List, A, B, C ), Y ).


% trojice ruznych prvku ze seznamu, serazene
threeMemsSort( List, A, B, C ) :-
    member( A, List ),
    member( B, List ),
    A @< B,
    member( C, List ),
    A @< C, B @< C.

kombinace3( List, Y ) :-
    findall( [A,B,C], threeMemsSort( List, A, B, C ), Y ).

aa(X) :- X = 0.
aa(X) :- X = 1, !.
aa(X) :- X = 2.
ba(X,Y) :- aa(X), aa(Y).
/*
* X = 0, Y = 0;
* X = 0, Y = 1;
* X = 1, Y = 0;
* X = 1, Y = 1.
*/

ab(X) :- X = 0.
ab(X) :- X = 1.
ab(X) :- X = 2.
bb(X,Y) :- ab(X), !, ab(Y).
/*
* X = 0, Y = 0;
* X = 0, Y = 1;
* X = 0, Y = 2.
*/

prime( X ) :- testPrime( 2, X ).

testPrime( P, P ) :- !. % zeleny rez
testPrime( D, P ) :-
    D < P, % zabezpeceni proti spatnemu pouziti
    P rem D =\= 0, % testujeme delitelnost
    D1 is D + 1,
    testPrime( D1, P ).

ff( a ).
ff( 1 ).
ff( 3 ).

filter( [], [] ).
filter( [X|XS], YSS ) :- ff( X ), !, YSS = [X|YS], filter( XS, YS ).
filter( [_|XS], YS ) :- filter( XS, YS ).
