Download
:- use_module(library(clpfd)). % Load the CLP library (Constraint Logic Programming)
% Solution is a list where the index is the column and the value is the row.
% n_queens_clp(+N, -Solution): Solution lists the row of the queen in each column
n_queens_clp(N, Solution) :-
length(Solution, N), % Create a list with N anonymous variables
Solution ins 1..N, % 1. Rule: Every number in the list must be between 1 and N (the rows).
all_different(Solution), % 2. Rule: No two queens can be in the same row.
safe_diagonals(Solution), % 3. Rule: No two queens can be on the same diagonal.
% FINDING THE SOLUTION
labeling([ff], Solution). % 'ff' (First-Fail): Picks the queen with the fewest possible options left and sets her first.
% Rules for Diagonals
% safe_diagonals(+Solution): posts constraints so no two queens share a diagonal
safe_diagonals(Solution) :-
length(Solution, N),
%creates list for the columns [1, 2, 3, ..., N]
numlist(1, N, Columns),
% Calculates a unique ID for every diagonal (with the functions sum_index and diff_index).
% maplist goes through the lists and stores the results in AscendingDiagonals and DescendingDiagonals.
maplist(sum_index, Solution, Columns, AscendingDiagonals), %Sum from Solution and Columns is stored in AscendingDiagonals
maplist(diff_index, Solution, Columns, DescendingDiagonals),
% Rule: all Diagonals must be unique
all_distinct(AscendingDiagonals),
all_distinct(DescendingDiagonals).
% Helper functions for the math
% sum_index(?Row, ?Col, ?Sum): Sum is the ascending-diagonal id Row + Col
sum_index(Row, Col, Sum) :- Sum #= Row + Col.
% diff_index(?Row, ?Col, ?Diff): Diff is the descending-diagonal id Row - Col
diff_index(Row, Col, Diff) :- Diff #= Row - Col.