2.11 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; assume that predicates 'perm' and 'takeout' are defined as in section 2.7.
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]).
Notice the inclusion of file lists.pro discussed in section 2.6. 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.


Prolog Code for this section.
Prolog Tutorial Contents