around(Prev,X,Next) :- Prev is X - 1, Next is X + 1.

swap_struct(X-Y, Y-X).

swap(A,Result) :- term_to_atom(T,A), First-Second=T, Swapped = Second-First, term_to_atom(Swapped, Result).
swap2(A,Result) :- term_to_atom(First-Second,A), term_to_atom(Second-First, Result).

area(rectangle(W,H), A) :- A is W * H.
area(circle(R), A) :- A is pi * R ** 2.
area(figure8(R1,R2), A) :- area(circle(R1),A1), area(circle(R2),A2), A is A1 + A2.

has_vowel(Atom) :-
	atom_chars(Atom,Chars),
	member(Char,Chars),
	member(Char,[a,e,i,o,u]).

printN(0).
printN(N) :- N > 0, M is N - 1, printN(M), writeln(N).

sumN(0,0).
sumN(N,Sum) :-
	N > 0, M is N - 1, sumN(M, Temp), Sum is Temp + N.

factorial(0,1). 

factorial(N,F) :-  
   N > 0, 
   N1 is N - 1, 
   factorial(N1,F1), 
   F is N * F1.

odd(1).
odd(N) :- odd(M), N is M + 2.

sumGreater(Target,N,Sum) :- between(1,inf,N), numlist(1,N,L), sumlist(L,Sum), Sum > Target.

empty([]).

eqlen(A1,A2) :- atom_chars(A1,C1), length(C1,Len),
    atom_chars(A2,C2), length(C2,Len).

starts_with(L, Prefix) :-
    append(Prefix,_,L).

take(L, N, Result) :-
    length(Result,N), append(Result, _, L).

take2(L, N, Result) :-
    append(Result, _, L), length(Result,N).

drop(L, N, Result) :-
    length(Dropped, N), append(Dropped, Result, L).

chunk(L,N,Chunk) :-
    length(Chunk,N),
    append(Chunk,_,L).

chunk(L,N,Chunk) :-
    length(Junk, N),
    append(Junk,Rest,L),
    chunk(Rest,N,Chunk).






	
first_last(L,First) :- append([First],_,L).
first_last(L,Last) :- append(_,[Last],L).












first_(L,First) :- append([First],_,L).
last_(L,Last) :- append(_,[Last],L).

first_last2(L,X) :- first_(L,X).
first_last2(L,X) :- last_(L,X).

head([X|_],X).

mem1(X,L) :- L = [X|_].
mem1(X,L) :- L = [_|T], mem1(X, T).

mem2(X,[X|_]).
mem2(X,[_|T]) :- mem2(X, T).

last1([X],X).
last1([_|T],X) :- last1(T,X).

len([], 0).
len([_|T],Len) :- len(T,TLen), Len is TLen + 1.

allsame([_]).
allsame([X,X|T]) :- allsame([X|T]).

listeq([],[]).
listeq([H|T],[H|T]) :- listeq(T,T).

listeq2([],[]).
listeq2([H|T],[H|T]).

myapp([], X, X).
myapp([X|L1], L2, [X|L3]) :-  myapp(L1, L2, L3).

% From Clause and Effect, p.43
drink(milk) :- true.       % Equivalent to drink(milk).
drink(beer) :- true, !.
drink(gin) :- true.


f(' f1 ').
f(' f2 ').
f(' f3 ').
g(' g1 ').
g(' g2 ').
g(' g3 ').

ce1(one,1) :- true.			% Equivalent to ce1(one,1).
ce1(two,2) :- true, !.
ce1(_, 'something') :- true.

grade(S,'A') :- S >= 90.
grade(S,'B') :- S >= 80, S < 90.
grade(S,'C') :- S >= 70, S < 80.
grade(S,'F') :- S < 70.


grade2(Score, 'A') :- Score >= 90.
grade2(Score, 'B') :- Score >= 80.
grade2(Score, 'C') :- Score >= 70.
grade2(_, 'F').

grade3(Score, 'A') :- Score >= 90, !.
grade3(Score, 'B') :- Score >= 80, !.
grade3(Score, 'C') :- Score >= 70, !.
grade3(_, 'F').

do_grades(Students) :-
    member(Who-Avg, Students),
    grade3(Avg,Grade),
    format('~w: ~w~n', [Who, Grade]), fail.


max0(X, Y, X) :- X >= Y.
max0(X, Y, Y) :- X < Y.

max(X,Y,X) :- X >= Y, !.
max(_,Y,Y).

%green_food(F) :- food(F), color(F,green), !.

/*
allpos([X]) :- X > 0.
allpos([X|T]) :- X > 0, allpos(T).
*/

allpos(L) :- member(X, L), X =< 0, !, fail.
allpos(_).

cant_prove(G) :- call(G), !, fail.
cant_prove(_).

% agf(F) :- food(F), color(F,green), !.

% makefoods and assert/retract predicates are in foods3.pl

as123([_]).
as123([X,X]).
as123([X,X,X]).

gen3(X,L) :- as123(L), nth0(0, L, X).

rev_atom(A,RA) :-		% warning: a rule shown in the middle of queries!
		reverse(AL,RL), atom_chars(A,AL), atom_chars(RA,RL).

/*
as123([X]).
as123([X,Y]) :- X = Y.
as123([X,Y,Z]) :- X = Y, Y = Z.
*/

rnumlist(High,Low,List) :- numlist(Low,High,List0), reverse(List0,List).

rnumlist2(High,Low,List) :- reverse(List0, List), numlist(Low,High,List0). % no return on second result

sumsegs(List, N, []) :- length(List,Len), Len < N.
sumsegs(List, N, Sums) :-
    length(Seg,N),
	append(Seg,Rest,List),
	sumlist(Seg,Sum),
	sumsegs(Rest,N,RestOfSums),
	append([Sum],RestOfSums,Sums).

gensums(List, N, Sum) :-
    chunk(List, N, Seg), sumlist(Seg, Sum).

evens([H|_],H) :- H rem 2 =:= 0.
evens([_|T],R) :- evens(T,R).

functor(S,F) :- S =.. [F|T], T \== [].
functor(S,F) :- S =.. [_,Left,_], functor(Left,F).
functor(S,F) :- S =.. [_,_,Right], functor(Right,F).

sumlists(Lists, Sums) :- findall(Sum, (member(List,Lists),sumlist(List,Sum)), Sums).

minsums(Lists, Min, Sums) :- findall(sum(List,Sum), (member(List,Lists),sumlist(List,Sum),Sum>=Min), Sums).

numlist_v1(Low, High, []) :- Low > High, !.
numlist_v1(Low, High, Result) :- Next is Low + 1, numlist_v1(Next, High, Rest), Result = [Low|Rest].

numlist(Low, High, []) :- Low > High, !.
numlist(Low, High, [Low|Rest]) :- Next is Low + 1, numlist(Next, High, Rest).

delete([], _, []).
delete([X|T], X, R) :- delete(T, X, R).
delete([E|T], X, [E|R]) :- E \== X, delete(T, X, R).

sf_gen([_,X|_], X).
sf_gen([X,_|_], X).
sf_gen([_,_|T],X) :- sf_gen(T,X).

% First noticed adjacent in Dr. Collberg's slides
adjacent(A,B,L) :- append(_, [A,B|_], L). 

oddd(1).
oddd(N) :- N rem 2 =:= 0, !, fail.
oddd(N) :- oddd(M), N is M + 2.
