/* Q1 Pt 1
Describe the map neighbourhood */
neighbour(a,b).
neighbour(a,c).
neighbour(a,d).
neighbour(a,i).
neighbour(b,a).
neighbour(b,c).
neighbour(b,d).
neighbour(c,a).
neighbour(c,b).
neighbour(c,d).
neighbour(c,f).
neighbour(c,g).
neighbour(c,i).
neighbour(d,a).
neighbour(d,b).
neighbour(d,c).
neighbour(d,e).
neighbour(d,f).
neighbour(e,d).
neighbour(e,f).
neighbour(e,h).
neighbour(f,c).
neighbour(f,d).
neighbour(f,e).
neighbour(f,g).
neighbour(f,h).
neighbour(g,c).
neighbour(g,f).
neighbour(g,h).
neighbour(g,i).
neighbour(h,e).
neighbour(h,f).
neighbour(h,g).
neighbour(h,i).
neighbour(i,a).
neighbour(i,c).
neighbour(i,g).
neighbour(i,h).
% X is the set of countries with no repetitions
countries(X) :-
setof(Y,N^neighbour(Y,N),X).
/* Q1 Pt 2
Map colourings */
colour(a,red).
colour(b,green).
colour(c,yellow).
colour(d,blue).
colour(e,blue).
colour(f,yellow).
colour(g,blue).
colour(h,yellow).
colour(i,green).
% Lists all distinct map colours used
colours(X) :-
setof(Y,N^colour(N,Y),X).
/*
Question 1 Pt 3
Query and answers to find out if the map
is perfectly coloured. It isn't.
?- colour(C1,Col), colour(C2,Col), neighbour(C1,C2).
C1 = c
Col = yellow
C2 = f ;
C1 = d
Col = blue
C2 = e ;
C1 = e
Col = blue
C2 = d ;
C1 = f
Col = yellow
C2 = c ;
C1 = f
Col = yellow
C2 = h ;
C1 = h
Col = yellow
C2 = f ;
No
*/
/* Q1 Pt 4
Find a path of countries
through the map */
path([X,Y]) :- % Only two countries.
neighbour(X,Y). % Path if they are neighbours.
path([X,Y|T]) :-
neighbour(X,Y), % Path if the first 2 countries
path([Y|T]). % are neighbours and the tail is a path.
/* Q1 Pt 5
Tour: a path through all the countries with no repetitions
and the last country is a neighbour of the first */
tour([H|T]) :-
length([H|T],9), % [H|L] contains 9 countries
path([H|T]), % and is a path.
append(_,[X],T),
neighbour(H,X), % 1st country neighbours the last.
setof(Y,member(Y,[H|T]),S),
length(S,9). % No repetitions.
% Another way to do it (I couldnt decide which is better):
tour2([H|T]) :-
length([H|T],9),
path([H|T]),
append(_,[K],T),
neighbour(H,K),
findall(X,(append(_,[X|R],[H|T]), member(X,R)),L),
L = []. % List of repetitions is empty.
/*
Find all tours starting with [a,b,c,d] :
?- tour([a,b,c,d|L]).
L = [e, f, g, h, i] ;
L = [e, f, h, g, i] ;
L = [e, h, f, g, i] ;
L = [f, e, h, g, i] ;
No
*/
/* Q1 Pt 6
Find tours where all consecutive countries
are a different colour */
perfect_tour([H|T]) :-
tour([H|T]),
% Find all of the places in T
% where two consecutive countries
% have the same colour
findall(X,(append(_,[X,Y|_],[H|T]),
append(_,[X,Y|_],[H|T]),colour(X,CX),colour(Y,CY),CX = CY),L),
L = [], % No same neighbouring colours found
append(_,[F],T),
colour(F,CF),
colour(H,CH),
CF \= CH. % and the colour of the first country
% is not the same as the last country.
/* Find all perfect tours
starting with [a,b,c]...
?- perfect_tour([a,b,c|T]).
T = [d, f, e, h, g, i] ;
T = [g, i, h, e, f, d] ;
T = [i, g, h, e, f, d] ;
No
*/
/* Q1 Pt 7
Find perfect colourings of the map */
perfect_map([],Colouring,_) :-
write(Colouring), nl, true. % Print list
perfect_map([Country|Countries],List,Colours) :-
member(Colour,Colours),
% Find all of the same coloured neighbours of a country
findall(Y,(neighbour(Country,Y), member([Y,Colour],List)),Same_Colour),
Same_Colour = [],
append(List,[[Country,Colour]],Next_List),
perfect_map(Countries,Next_List,Colours).
/*
Takes a list of colours and prints a perfect map
colouring as a list of [Country,Colour] pairs. */
perfect_map :-
Colours = [red,yellow,blue,green],
countries([Country|Countries]),
perfect_map(Countries,[[Country,red]],Colours).
/*
Output:
?- perfect_map.
[[a, red], [b, yellow], [c, blue], [d, green], [e, red], [f, yellow], [g, red],
[h, blue], [i, yellow]]
*/
/* Q2 Pt 1
Find the smallest element in a list */
min_in_list([Min],Min). % We've found the minimum
min_in_list([H,K|T],M) :-
H =< K, % H is less than or equal to K
min_in_list([H|T],M). % so use H
min_in_list([H,K|T],M) :-
H > K, % H is greater than K
min_in_list([K|T],M). % so use K
/* Q2 Pt 2
Find a list of elements that occur only once in another list */
not_member(K,L) :- member(K,L),!, fail.
not_member(_,_).
list_of_singletons(K,L) :-
% Find list of duplicated items in K
findall(Y,(member(Y,K),append(_,[Y|T],K),member(Y,T)),X),
% Find items in K that are not duplicates
findall(A,(member(A,K),not_member(A,X)),L).
/* Q2 Pt 3
Find the winning number and student number */
:- ensure_loaded([list_of_bets]). % Use data in list_of_bets.pl
winning_number(N) :-
findall(Y,bet(_,Y),K), % List the bet numbers
list_of_singletons(K,L), % Remove duplicates
min_in_list(L,N). % Get the lowest number
/*
?- winning_number(Number), bet(Student,Number).
Number = 3
Student = 330734 ;
No
*/
/* Q3
Output Pascal's triangle of height given by user */
pascal :-
write('Enter a number followed by "." :> '),
read(N),
integer(N), % Check that input is an integer
pascal(N,[1],0).
pascal(N,L,I) :-
J is I + 1,
write(L), nl, % Write the current line
J =< N,
pascal_next_line([0|L],NL), % Get the next line
pascal(N,NL,J). % Recurse to the next line
pascal_next_line([X],[X]).
pascal_next_line([H,H2|T],[A|B]) :-
pascal_next_line([H2|T],B), % Work out each number from the ones
A is H + H2. % diagonally above it.