As part of my earlier studies into Artificial Intelligence, I was challenged to write a prolog program to solve the knight’s tour for an 8×8 board. I had early success using UNSW4 prolog interperter on SCO Unix machine, and the program resolved a path in 45 minutes in early 1995. Later that year, using the same prolog program and prolog interperter, the program resolved the knight’s tour on Sparc Center 2000 in 25 minutes. In my opinion I accomplished quite a feat. My code was influenced by Clocksin and Mellish book Programming in Prolog, which had an example of depth first search algorithm.
Here is the original prolog code for UNSW prolog interperter.
% The knight's tour puzzle for an 8x8 board.
% Written by Robert Borrell
%
% To find solution,
% type knight_tour([1,8], X)? on interpreter line.
%
% The following clauses are from Programming in Prolog by Clocksin
% and Mellish:
%
% membership,
% rev, and
% append
%
% Verify clause
verify(X,Y) :- X > 0 , X < 9, Y > 0 , Y < 9.
%
% Knight move rules
%
knight_move([R,C],[X,Y]) :- X is R + 2 , Y is C + 1 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R + 1 , Y is C + 2 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R - 1 , Y is C + 2 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R - 2 , Y is C + 1 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R + 2 , Y is C - 1 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R - 2 , Y is C - 1 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R - 1 , Y is C - 2 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R + 1 , Y is C - 2 , verify(X,Y).
%
% Classical membership test
%
member(X,[X|T]).member(X,[H|T]) :- member(X,T).
%
% Depth Search Algorithm dervived from Programming in Prolog
%
go0(Place,T,R,L) :-
knight_move(Place,Next),
not(member(Next,T)),
go0(Next,[Place|T],R,L1),
L is L1 + 1.go0(X,T,[X|T], 1).
%
% Classical rev clause
%
rev([],[]).
rev([H|T],L) :- rev(T,Z), append(Z,[H],L).
%
% Classical append clause
%
append([],L,L).
append([X|L1],L2,[X|L3]) :- append(L1,L2,L3).
%
% knight_tour clause
%
knight_tour(Start, Solution) :-
go0(Start, [], R, Len),
Len == 64,
rev(R, Solution),
!.
Recently I have ported the UNSW prolog interperter to a RHEL 4.5 in VMWare environment on a PC running 3.0 GHz Intel processor. The result was the program resolved a path in 35 seconds.
However, I modified the same code above and ported to GNU Prolog, the result is simpler:
%
% Verify clause
%
verify(X,Y) :- X > 0 , X < 9, Y > 0 , Y < 9.
%
% Knight move rules
%
knight_move([R,C],[X,Y]) :- X is R + 2 , Y is C + 1 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R + 1 , Y is C + 2 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R - 1 , Y is C + 2 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R - 2 , Y is C + 1 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R + 2 , Y is C - 1 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R - 2 , Y is C - 1 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R - 1 , Y is C - 2 , verify(X,Y).
knight_move([R,C],[X,Y]) :- X is R + 1 , Y is C - 2 , verify(X,Y).
%
% Depth Search Algorithm dervived from Programming in Prolog
%
go0(X,T,[X|T]).
go0(Place,T,R) :-
knight_move(Place,Next),
not(member(Next,T)),
go0(Next,[Place|T],R).
%
% knight_tour clause
%
knight_tour(Start, Solution) :-
go0(Start, [], R),
length(R, Len),
Len == 64,
reverse(R, Solution).
The irony is that Luger in Artificial Intelligence: Structures and Strategies for Complex Problem Solving treats the knight’s tour problem as a simple student exercise, in which he not only challenges the student to resolve in Prolog, but also in LISP, the premier AI programming language for which I have little experience with.