Download
/*
N-Queens problem in Picat.
Model created by Hakan Kjellerstrand, hakank@gmail.com
See also my Picat page: http://www.hakank.org/picat/
*/
% Licenced under CC-BY-4.0 : http://creativecommons.org/licenses/by/4.0/
import util.
import cp.
main => go.
%
% Note that $Q[I] is needed here.
%
queens3(N, Q) =>
Q=new_list(N),
Q :: 1..N,
all_different(Q),
all_different([$Q[I]-I : I in 1..N]),
all_different([$Q[I]+I : I in 1..N]),
solve([ff],Q).
queens3(N) =>
queens3_all(N, Solutions),
% writeln(Solutions),
writeln(len=Solutions.length).
% generate all solutions via solve_all (don't work right now)
queens3_all(N, Solutions) =>
Q=new_list(N),
Q :: 1..N,
all_different(Q),
all_different([$Q[I]-I : I in 1..N]),
all_different([$Q[I]+I : I in 1..N]),
% This yield "Unknown procedure solve/2".
Solutions = solve_all([ff],Q).
% This works:
% Solutions = findall(Q, $solve($Q)).
% Using all_distinct instead
queens3b(N, Q) =>
Q=new_list(N),
Q :: 1..N,
all_distinct(Q),
all_distinct([$Q[I]-I : I in 1..N]),
all_distinct([$Q[I]+I : I in 1..N]),
solve([ff],Q).
% alternative approaches
queens4(N, Q) =>
Q = new_list(N),
Q :: 1..N,
foreach(A in [-1,0,1])
all_different([$Q[I]+I*A : I in 1..N])
end,
solve([ff],Q).
% Decomposition of alldifferent
all_different_me(L) =>
Len = length(L),
foreach(I in 1..Len, J in I+1..Len) L[I] #!= L[J] end.
% Using all_different_me (my decomposition)
queens5(N, Q) =>
Q=new_list(N),
Q :: 1..N,
all_different_me(Q),
all_different_me([$Q[I]-I : I in 1..N]),
all_different_me([$Q[I]+I : I in 1..N]),
solve([ff],Q).
go =>
queens3(8,Q),
writeln(Q),
N2 = 12,
queens3_all(8, Solutions),
% writeln(Solutions),
Len=Solutions.length,
writef("N:%w %w solutions.\n%w\n", N2, Len, Solutions).
go2 =>
foreach(N in 2..14)
statistics(backtracks, Backtracks),
statistics(runtime, [_, _Runtime1]),
queens3_all(N, Solutions),
Len=Solutions.length,
statistics(backtracks, Backtracks2),
B = Backtracks2 - Backtracks,
Backtracks := Backtracks2,
statistics(runtime, [_, Runtime2]),
writef("N:%3d %10d solutions (%d backtracks, %d millis)\n", N, Len, B, Runtime2)
end.
%
% Times per Picat v 0.1-beta 10:
% queens3 : 6.7s (2 backtracks)
% queens3b: 10.83s (0 backtracks)
% queens4 : 4.25s (2 backtracks)
% queens5 : 6.86s (2 backtracks)
%
go3 =>
Ps = [queens3=1000, queens3b=1000, queens4=1000,queens5=1000],
foreach(P=N in Ps)
printf("%w(%d)\n", P, N),
time2(once(call(P,N,Q))),
writeln(Q),
nl
end.
% Using permutations/1. Very slow.
go4 =>
N = 8,
C = 0,
foreach(P in permutations(1..N))
if check4(P) then
% writeln(P),
C := C +1
end
end,
writeln(sols=C),
nl.
go5 =>
N=100,
queens3(N,Q),
writeln(Q),
nl.
go6 =>
N = 10000,
println("timing queens4(10000,Q)"),
time2(queens4(N,_Q)),
nl.
check4(P) =>
N = length(P),
foreach(I in 1..N, J in I+1..N)
P[I]-I != P[J]-J,
P[I]+I != P[J]+J
end.