Chess queens challenge puzzle
The challenge is to set N queens on an NxN grid so that no queen can "take"
any other queen. Queens can move horizontally, vertically, or along a (45%)
diagonal. The following diagram shows a solution for N=4 queens.
________________
| | | Q | |
|___|___|___|___|
| Q | | | |
|___|___|___|___|
| | | | Q |
|___|___|___|___|
| | Q | | |
|___|___|___|___|
A solution to this puzzle can be represented as a special permutation of
the list [1,2,3,4]. For example, the solution pictured above can be represented
as [3,1,4,2], meaning that, in the first row place a queen in column 3,
in the second row place a queen in column 1, etc. To test whether a given
permutation is a solution, one needs to calculate whether the permutation
has (or represents a situation where) two or more queens lie on the same
diagonal. The representation itself prevents two or more queens in the
same row or column. Two queens are on the same / diagonal if and only if
the sum of the row and column is the same for each; they are on the same
\ diagonal if and only if the difference of their row and column is the
same number. The following Prolog program has the details.
solve(P) :-
perm([1,2,3,4,5,6,7,8],P),
combine([1,2,3,4,5,6,7,8],P,S,D),
all_diff(S),
all_diff(D).
combine([X1|X],[Y1|Y],[S1|S],[D1|D]) :-
S1 is X1 +Y1,
D1 is X1 - Y1,
combine(X,Y,S,D).
combine([],[],[],[]).
all_diff([X|Y]) :- \+member(X,Y), all_diff(Y).
all_diff([X]).
takeout(X,[X|R],R).
takeout(X,[F|R],[F|S]) :- takeout(X,R,S).
These clauses for takeout can be paraphrased in English as follows:
-
When X is taken out of [X|R], R results.
-
When X is taken out of the tail of [X|R], [X|S] results, where S is
the result of taking X out of R.
For example,
?- takeout(X,[1,2,3],L).
X=1 L=[2,3] ;
X=2 L=[1,3] ;
X=3 L=[1,2] ;
No
The definition for 'member' is usually written
member(X,[X|_]).
member(X,[_|R]) :- member(X,R).
This is
a nice, simple specification that uses 'perm' to generate possible solutions
to the puzzle. A sample goal is
?- solve(P).
P = [5,2,6,1,7,4,8,3] ;
P = [6,3,5,7,1,4,2,8] ;
...
?- setof(P,solve(P),Set), length(Set,L).
...
L = 92
The last goal reflects the fact that there are 92 distinct solutions to
the queens challenge puzzle for an 8x8 board. One inefficiency that this
program suffers is that each permutation is completely calculated before
it is checked to see whether it represents a solution to the puzzle. It
is easy to see that this is not necessary. For example, suppose that a
"partial solution" P = [1,3,2, ...] is up for consideration. The row and
column calculations show already the "2" is not a safe move! A solution
that avoids this inefficiency is considered in section 2.13.