:- [adts].

move(1,6).
move(1,8).
move(2,7).
move(2,9).
move(3,4).
move(3,8).
move(4,3).
move(4,9).
move(6,7).
move(6,1).
move(7,6).
move(7,2).
move(8,3).
move(8,1).
move(9,4).
move(9,2).

unsafe(0).

%%%%%%% Breadth first search algorithm%%%%%%%%
	
go(Start, Goal) :- 
	empty_queue(Empty_open_queue),
	enqueue([Start, nil], Empty_open_queue, Open_queue),
	empty_set(Closed_set),
	path(Open_queue, Closed_set, Goal).

path(Open_queue, _, _) :- empty_queue(Open_queue),
        write('graph searched, no solution found').
	
path(Open_queue, Closed_set, Goal) :- 
	dequeue([State, Parent], Open_queue, _),
	State = Goal,
	write('Solution path is: '), nl,
	printsolution([State, Parent], Closed_set).
	
path(Open_queue, Closed_set, Goal) :- 
	dequeue([State, Parent], Open_queue, Rest_of_open_queue),
        get_children(State, Rest_of_open_queue, Closed_set, Children),
	add_list_to_queue(Children, Rest_of_open_queue, New_open_queue), 
	union([[State, Parent]], Closed_set, New_closed_set),
	path(New_open_queue, New_closed_set, Goal),!.

get_children(State, Rest_of_open_queue, Closed_set, Children) :-
        bagof(Child, moves(State, Rest_of_open_queue, Closed_set, Child),
             Children); 
        empty_set(Children).
moves(State, Rest_of_open_queue, Closed_set, [Next, State]) :-
	move(State, Next),
        not(unsafe(Next)),
	not(member_queue([Next, _], Rest_of_open_queue)),
	not(member_set([Next, _], Closed_set)).

printsolution([State, nil], _):- 
	write(State), nl.
printsolution([State, Parent], Closed_set) :-
	member_set([Parent, Grandparent], Closed_set),
	printsolution([Parent, Grandparent], Closed_set),
	write(State), nl.
