Best First Search
% ---------------------------------------------------- % Alan Lupsha % Knight's tour - using best-first search % June 4th, 2007 % ---------------------------------------------------- :- [adts]. state_record(State, Parent, G, H, F, [State, Parent, G, H, F]). precedes([_,_,_,_,F1], [_,_,_,_,F2]) :- F1 =< F2. go(Start,Goal) :- empty_set(Closed), empty_sort_queue(Empty_open), heuristic(Start,Goal,H), state_record(Start, nil, 0, H, H, First_record), insert_sort_queue(First_record,Empty_open,Open), path(Open,Closed,Goal). path(Open,_,_) :- empty_sort_queue(Open), write('No solution found with these rules'). path(Open, Closed, Goal) :- remove_sort_queue(First_record, Open, _), state_record(State, _, _, _, _, First_record), State = Goal, write('A solution is found!'), nl, printsolution(First_record, Closed). path(Open, Closed, Goal) :- remove_sort_queue(First_record, Open, Rest_of_open), (bagof(Child, moves(First_record, Open, Closed, Child, Goal), Children);Children = []), insert_list(Children, Rest_of_open, New_open), add_to_set(First_record, Closed, New_closed), path(New_open, New_closed, Goal),!. moves(State_record,Open,Closed,Child,Goal) :- state_record(State,_,G,_,_,State_record), move(State,Next), state_record(Next,_,_,_,_,Test), not(member_sort_queue(Test,Open)), not(member_set(Test,Closed)), G_new is G + 1, heuristic(Next, Goal, H), F is G_new + H, state_record(Next, State, G_new, H, F, Child). insert_list([], L, L). insert_list([State | Tail], L, New_L) :- insert_sort_queue(State, L, L2), insert_list(Tail, L2, New_L). printsolution(Next_record, _):- state_record(State, nil, _,_,_, Next_record), write(State), nl. printsolution(Next_record, Closed) :- state_record(State, Parent, _,_,_, Next_record), state_record(Parent, _, _, _, _, Parent_record), member_set(Parent_record, Closed), printsolution(Parent_record, Closed), write(State), nl. % 1 2 3 % 4 5 6 % 7 8 9 move(1,8). heuristic(1,8,0). move(1,6). heuristic(1,6,1). move(2,7). heuristic(2,7,1). move(2,9). heuristic(2,7,0). move(3,4). heuristic(3,4,0). move(3,8). heuristic(3,4,1). move(4,3). heuristic(4,3,1). move(4,9). heuristic(4,3,0). move(6,1). heuristic(6,1,1). move(6,7). heuristic(6,7,0). move(7,2). heuristic(7,2,0). move(7,6). heuristic(7,2,1). move(8,1). heuristic(8,1,1). move(8,3). heuristic(8,3,0). move(9,4). heuristic(9,4,0). move(9,2). heuristic(9,2,1). heuristic(X,Y,0).
Example run
% c:/alan/prolog/knight-best.pl compiled 0.00 sec, 16,596 bytes Welcome to SWI-Prolog (Multi-threaded, Version 5.6.34) Copyright (c) 1990-2007 University of Amsterdam. SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Please visit http://www.swi-prolog.org for details. For help, use ?- help(Topic). or ?- apropos(Word). 1 ?- go(1,3). A solution is found! 1 8 3 Yes 2 ?- go(1,9). A solution is found! 1 6 7 2 9 Yes 3 ?- go(1,5). No solution found with these rules Yes 4 ?-
Breadth First Search
% ---------------------------------------------------- % Alan Lupsha % Knight's tour - using breadth-first search % June 4th, 2007 % ---------------------------------------------------- :- [adts]. state_record(State, Parent, [State, Parent]). go(Start,Goal) :- empty_queue(Empty_open), state_record(Start, nil, State), add_to_queue(State, Empty_open, Open), empty_set(Closed), path(Open,Closed,Goal). path(Open,_,_) :- empty_queue(Open), write('No solution found with these rules'). path(Open,Closed,Goal) :- remove_from_queue(Next_record,Open,_), state_record(State, _, Next_record), State = Goal, write('A solution is found!'), nl, printsolution(Next_record,Closed). path(Open,Closed,Goal) :- remove_from_queue(Next_record,Open,Rest_Open), (bagof(Child, moves(Next_record, Open, Closed, Child), Children);Children = []), add_list_to_queue(Children,Rest_Open,New_Open), add_to_set(Next_record, Closed, New_Closed), path(New_Open,New_Closed,Goal),!. moves(State_record,Open,Closed,Child_record) :- state_record(State,_,State_record), move(State,Next), state_record(Next,_,Test), not(member_queue(Test,Open)), not(member_set(Test,Closed)), state_record(Next,State,Child_record). printsolution(State_record, _) :- state_record(State,nil,State_record), write(State), nl. printsolution(State_record,Closed) :- state_record(State, Parent, State_record), state_record(Parent, _, Parent_record), member(Parent_record,Closed), printsolution(Parent_record,Closed), write(State),nl. % 1 2 3 % 4 5 6 % 7 8 9 move(1,8). move(1,6). move(2,7). move(2,9). move(3,4). move(3,8). move(4,3). move(4,9). move(6,1). move(6,7). move(7,2). move(7,6). move(8,1). move(8,3). move(9,4). move(9,2). unsafe(0). add_to_queue(E, [], [E]). add_to_queue(E, [H|T], [H|Tnew]) :- add_to_queue(E, T, Tnew). add_list_to_queue([], Queue, Queue). add_list_to_queue([H|T], Queue, New_queue) :- add_to_queue(H, Queue, Temp_queue), add_list_to_queue(T, Temp_queue, New_queue). enqueue( X, Y, Z ) :- add_to_queue(X, Y, Z). % Redefined using file adts dequeue( X, Y, Z ) :- remove_from_queue(X, Y, Z). % Redefined using file adts
Example run:
% c:/documents and settings/wise grasshopper/pl.ini compiled 0.00 sec, 512 bytes Warning: (c:/alan/prolog/adts:7): Singleton variables: [T] Warning: (c:/alan/prolog/adts:8): Singleton variables: [Y] Warning: (c:/alan/prolog/adts:74): Singleton variables: [E] % adts compiled 0.00 sec, 10,584 bytes Warning: (c:/alan/prolog/knight-breadth.pl:79): Redefined static procedure add_to_queue/3 % c:/alan/prolog/knight-breadth.pl compiled 0.00 sec, 15,112 bytes Welcome to SWI-Prolog (Multi-threaded, Version 5.6.34) Copyright (c) 1990-2007 University of Amsterdam. SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Please visit http://www.swi-prolog.org for details. For help, use ?- help(Topic). or ?- apropos(Word). 1 ?- go(1,3). A solution is found! 1 8 3 Yes 2 ?- go(1,9). A solution is found! 1 8 3 4 9 Yes 3 ?- go(1,5). No solution found with these rules Yes 4 ?-
Depth First Search
% ---------------------------------------------------- % Alan Lupsha % Knight's tour - using depth-first search % June 4th, 2007 % ---------------------------------------------------- :- [adts]. 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. go(Start,Goal) :- empty_stack(Empty_open), stack([Start,nil], Empty_open, Open_stack), empty_set(Closed_set), path(Open_stack,Closed_set,Goal). path(Open_stack,_,_) :- empty_stack(Open_stack), write('No solution found with these rules'). path(Open_stack,Closed_set,Goal) :- stack([State,Parent],_,Open_stack), State=Goal, write('A solution is found!'), nl, printsolution([State, Parent],Closed_set). path(Open_stack,Closed_set,Goal) :- stack([State,Parent],Rest_open_stack,Open_stack), get_children(State,Rest_open_stack,Closed_set,Children), add_list_to_stack(Children,Rest_open_stack,New_open_stack), union([[State,Parent]],Closed_set,New_closed_set), path(New_open_stack,New_closed_set,Goal),!. get_children(State,Rest_open_stack,Closed_set,Children) :- bagof(Child,moves(State,Rest_open_stack,Closed_set,Child), Children). moves(State,Rest_open_stack,Closed_set,[Next,State]) :- move(State,Next), not(unsafe(Next)), not(member_stack([Next,_],Rest_open_stack)), not(member_set([Next,_],Closed_set)). % 1 2 3 % 4 5 6 % 7 8 9 move(1,8). move(1,6). move(2,7). move(2,9). move(3,4). move(3,8). move(4,3). move(4,9). move(6,1). move(6,7). move(7,2). move(7,6). move(8,1). move(8,3). move(9,4). move(9,2). unsafe(0). add_to_queue(E, [], [E]). add_to_queue(E, [H|T], [H|Tnew]) :- add_to_queue(E, T, Tnew). add_list_to_stack( NewList , OldList , ResultList ) :- append( NewList, OldList, ResultList ).
Example run:
% c:/documents and settings/wise grasshopper/pl.ini compiled 0.00 sec, 512 bytes Warning: (c:/alan/prolog/adts:7): Singleton variables: [T] Warning: (c:/alan/prolog/adts:8): Singleton variables: [Y] Warning: (c:/alan/prolog/adts:74): Singleton variables: [E] % adts compiled 0.00 sec, 10,584 bytes Warning: (c:/alan/prolog/knight-depth.pl:65): Redefined static procedure add_to_queue/3 % c:/alan/prolog/knight-depth.pl compiled 0.02 sec, 14,668 bytes Welcome to SWI-Prolog (Multi-threaded, Version 5.6.34) Copyright (c) 1990-2007 University of Amsterdam. SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Please visit http://www.swi-prolog.org for details. For help, use ?- help(Topic). or ?- apropos(Word). 1 ?- go(1,2). A solution is found! 1 8 3 4 9 2 Yes 2 ?- go(1,9). A solution is found! 1 8 3 4 9 Yes 3 ?- go(1,5). No 4 ?-
Knight’s Tour – operations
%%%%%%%%%%%%%%%%%%%% stack operations %%%%%%%%%%%%%%%%%%%%%%%%%%%%% % These predicates give a simple, list based implementation of stacks % empty stack generates/tests an empty stack member(X,[X|T]). member(X,[Y|T]):-member(X,T). empty_stack([]). % member_stack tests if an element is a member of a stack member_stack(E, S) :- member(E, S). % stack performs the push, pop and peek operations % to push an element onto the stack % ?- stack(a, [b,c,d], S). % S = [a,b,c,d] % To pop an element from the stack % ?- stack(Top, Rest, [a,b,c]). % Top = a, Rest = [b,c] % To peek at the top element on the stack % ?- stack(Top, _, [a,b,c]). % Top = a stack(E, S, [E|S]). %%%%%%%%%%%%%%%%%%%% queue operations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % These predicates give a simple, list based implementation of % FIFO queues % empty queue generates/tests an empty queue empty_queue([]). % member_queue tests if an element is a member of a queue member_queue(E, S) :- member(E, S). % add_to_queue adds a new element to the back of the queue add_to_queue(E, [], [E]). add_to_queue(E, [H|T], [H|Tnew]) :- add_to_queue(E, T, Tnew). % remove_from_queue removes the next element from the queue % Note that it can also be used to examine that element % without removing it remove_from_queue(E, [E|T], T). append_queue(First, Second, Concatenation) :- append(First, Second, Concatenation). %%%%%%%%%%%%%%%%%%%% set operations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % These predicates give a simple, % list based implementation of sets % empty_set tests/generates an empty set. empty_set([]). member_set(E, S) :- member(E, S). % add_to_set adds a new member to a set, allowing each element % to appear only once add_to_set(X, S, S) :- member(X, S), !. add_to_set(X, S, [X|S]). remove_from_set(E, [], []). remove_from_set(E, [E|T], T) :- !. remove_from_set(E, [H|T], [H|T_new]) :- remove_from_set(E, T, T_new), !. union([], S, S). union([H|T], S, S_new) :- union(T, S, S2), add_to_set(H, S2, S_new). intersection([], _, []). intersection([H|T], S, [H|S_new]) :- member_set(H, S), intersection(T, S, S_new),!. intersection([_|T], S, S_new) :- intersection(T, S, S_new),!. set_diff([], _, []). set_diff([H|T], S, T_new) :- member_set(H, S), set_diff(T, S, T_new),!. set_diff([H|T], S, [H|T_new]) :- set_diff(T, S, T_new), !. subset([], _). subset([H|T], S) :- member_set(H, S), subset(T, S). equal_set(S1, S2) :- subset(S1, S2), subset(S2, S1). %%%%%%%%%%%%%%%%%%%%%%% priority queue operations %%%%%%%%%%%%%%%%%%% % These predicates provide a simple list based implementation % of a priority queue. % They assume a definition of precedes for the objects being handled empty_sort_queue([]). member_sort_queue(E, S) :- member(E, S). insert_sort_queue(State, [], [State]). insert_sort_queue(State, [H | T], [State, H | T]) :- precedes(State, H). insert_sort_queue(State, [H|T], [H | T_new]) :- insert_sort_queue(State, T, T_new). remove_sort_queue(First, [First|Rest], Rest).