QUEENS : N = 11
Updated : 23 May 2022 @ 12:10:07
1. DESCRIPTION OF THE PROBLEM
Problem of N independant queens
- question
solve (N)
--> should print correctly all solutions
- difficulties
- il faut trouver sur un échiquier carré de taille N coment positionner N dames sans prise mutuelle
2. DIFFICULTIES
model the solving process
print a solution
example
3. MODEL OF THE PROBLEM
if Ln = [1, 2, ..., N]
a queen in row i is in row Ln [i]
find a permutation of Ln such that queens can not catch each other.
constraints
- not same line
from the model in Ln
- not same column
from the model in Ln
all different numbers
- not same diagonal
should check 2 directions
solve by trying first 2, 3, ... N queens
while respecting constraints
4. USER'S MANUAL
queries
- q1 ( N )
find first solution for N
- qf (N)
Find all solutions for N
- ql(N)
finds a solution for N if N is prime
examples of solutions
N = 29
algorithm in linear time for K not multiple of 2 nor 3
5. structure
solve_queens
        list_range
        solve_queens_2
                member_reste
                diagonal_ok
        display_board
                display_line
                        display_queen_1
6. Code in prolog
:- encoding(utf8).
% le code
/*
start
DESCRIPTION OF THE PROBLEM
Problem of N independant queens
question
solve (N)
--> should print correctly all solutions
difficulties
il faut trouver sur un échiquier carré de taille N coment positionner N dames sans prise mutuelle
DIFFICULTIES
2COLUMNS
model the solving process
print a solution
example
MODEL OF THE PROBLEM
if Ln = [1, 2, ..., N]
a queen in row i is in row Ln [i]
find a permutation of Ln such that queens can not catch each other.
constraints
not same line
from the model in Ln
not same column
from the model in Ln
all different numbers
not same diagonal
should check 2 directions
solve by trying first 2, 3, ... N queens
while respecting constraints
USER'S MANUAL
queries
q1 ( N )
find first solution for N
qf (N)
Find all solutions for N
ql(N)
finds a solution for N if N is prime
examples of solutions
BOLD
2COLUMNS
N = 29
algorithm in linear time for K not multiple of 2 nor 3
structure
solve_queens
list_range
solve_queens_2
member_reste
diagonal_ok
display_board
display_line
display_queen_1
Code in prolog
BR
PRE
CODE
*insert
cf : QUEENS.pl
*/
:- use_module(library(pce)).
% utilitaires
:- encoding(utf8).
% macros utiles PROLOG
% >>> ================================== iteritems =============================================
iteritems(L, X, N) :-
iteritems_1(L, 1, X, N).
% >>> ------------------------------------------ iteritems_1 ( +Liste, +Max , -Elt, -Rang)---------------------------
% DOC
% prédicat iteritems_1 ( +Liste, +Max , -Elt, -Rang)
/*
for a list [a, b, c], will produce :
(a,1), (b, 2), etc
Syntax
iteritems (+L, -X, -N)
*/
% .
% X .. L , K
% X, K
iteritems_1([X | L], K, X, K).
iteritems_1([X | L], K, X1, K1) :-
K2 is K + 1,
iteritems_1(L, K2, X1, K1).
% <<<------------------------------------------ iteritems_1 ( +Liste, +Max , -Elt, -Rang) ---------------------------
% <<< ================================== iteritems =============================================
% >>> ================================== member_num (+X, +L, -N) =============================================
% trouve l'indice N de X dans L, sinion fail
% démarre à 1
member_num(X, L, N) :-
member_num_1(X, L, N, 1).
member_num_1(X,[X | L], K, K) :-
!.
member_num_1(X,[Y | L], K, K1) :-
K2 is K1 + 1,
member_num_1(X, L, K, K2).
% <<< ================================== member_num (+X, +L, -N) =============================================
% >>> ================================== ECRITURES SUR LE TERMINAL =============================================
/*
Pour imprimer une liste avec write
exemples
write_item ([a, b , nl, foo(1, 2), [1, 2, 3] ] )
?- L = [1, 2, nl, 4, 5, foo(x,y), [r, e, "dfghjk"] ], write_item(L).
12
45foo(x,y)[r,e,dfghjk]
L = [1, 2, nl, 4, 5, foo(x, y), [r, e|...]].
?- L = [1, 2, nl, 4, 5, foo(x,y), [r, e, "dfghjk"] ], write_item(L, " ").
1 2
4 5 foo(x,y) [r,e,dfghjk]
L = [1, 2, nl, 4, 5, foo(x, y), [r, e|...]].
?- L = [1, 2, nl, 4, 5, foo(x,y), [r, e, "dfghjk"] ], write_item(L, ",").
1,2,
4,5,foo(x,y),[r,e,dfghjk],
L = [1, 2, nl, 4, 5, foo(x, y), [r, e|...]].
syntaxe
write_item (X)
imprime les éléments de X si X est une liste
sinon imprime X
ajoute un nl à la fin
write_item (X, Sep)
idem, mais ajoute le séparateur Sep entre les items imprimés
*/
% write_item : 2 versions :1 et /2
% >>> ------------------------------------------ write_item ( X) ---------------------------
% DOC
% prédicat write_item ( X)
write_item([X | L]) :-
!,
(
member(Y,[X | L]),
(
Y = nl
->
nl
;
write_item(Y)
),
fail
;
true
),
nl.
write_item(X) :-
write(X),
nl,
!.
% <<<------------------------------------------ write_item ( X)---------------------------
% >>> ------------------------------------------ write_item ( X, Sep) ---------------------------
% DOC
% prédicat write_item ( X, Sep)
write_item([X | L], Sep) :-
!,
(
member(Y,[X | L]),
(
Y = nl
->
nl,
!
;
write(Y),
write(Sep)
),
fail
;
true
),
nl.
write_item(X , _) :-
write(X),
nl,
!.
% <<<------------------------------------------ write_item ( X, Sep)---------------------------
% <<< ================================== ECRITURES SUR LE TERMINAL =============================================
% >>> ================================== COUNTERS =============================================
init_counter(Name) :-
nb_setval(Name, 0).
init_counter(Name, Value) :-
nb_setval(Name, Value).
incr_counter(Name) :-
nb_getval(Name, C),
CNew is C + 1,
nb_setval(Name, CNew).
incr_counter(Name, Incr) :-
nb_getval(Name, C),
CNew is C + Incr,
nb_setval(Name, CNew).
incr_counter_v(Name, CNew) :-
nb_getval(Name, C),
CNew is C + 1,
nb_setval(Name, CNew).
val_counter(Name, V) :-
nb_getval(Name, V).
% <<< ================================== COUNTERS =============================================
% >>> ================================== FOR USER INTERACTION =============================================
/*
a few predicates and macros to have more readable code
for demo for Laurent chaudron
say ::=
*vars
{say_}
say_ = a0 [4:]
write_info ([{say_}])
{L}
*/
write_info(L) :-
write_info_1(L),
!,
nl.
% >>> ------------------------------------------ write_info_1 ( +Info) ---------------------------
% DOC
% prédicat write_info_1 ( +Info)
write_info_1([]) :-
!.
write_info_1([X | L]) :-
!,
write_info_1(X),
write(" "),
write_info_1(L).
write_info_1(found(X)) :-
write(found),
!,
write(" "),
write_info_1(X).
write_info_1(board(B)) :-
!,
length(B, N),
nl,
display_board(B, N).
write_info_1(board(B, N)) :-
!,
display_board(B, N).
write_info_1(([X | L])) :-
!,
write_info_1([X | L]).
write_info_1(Any) :-
write(Any).
% <<<------------------------------------------ write_info_1 ( +Info)---------------------------
% <<< ================================== FOR USER INTERACTION =============================================
% probleme des N QUEENS
% affichage
display_queen_1 :-
write("♛").
display_line(K, N, M) :-
(
M > N
->
!,
write('|'),
nl,
fail
;
(
K = M
->
display_queen_1
;
write(" ")
)
),
M1 is M +1,
!,
display_line(K, N, M1).
display_board(Sol, N) :-
(
iteritems(Sol, Elt, K),
write('|'),
display_line(Elt, N, 1),
fail
;
true
).
% affichage
/*
display _queens
INPUT
L = liste of positions in rows
N = number of queens
*/
% >>> ------------------------------------------ display_queens ( (L, N)) ---------------------------
% DOC
% prédicat display_queens ( (L, N))
% Sous-sujet 2
display_queens(L, _, 0).
display_queens([X | L ], Compteur) :-
C2 is Compteur + 1,
display_queens(L, N, C2).
% <<<------------------------------------------ display_queens ( (L, N))---------------------------
% solution du problème
% fabrication d'une liste [8, 7, 6, 5 .... 1]
% >>> ------------------------------------------ liste_range ((N, L)) ---------------------------
% DOC
% prédicat liste_range ((N, L))
% nothing
liste_range(0,[]) :-
!.
liste_range(K, [K | L]) :-
K > 0,
K1 is K-1,
liste_range(K1, L).
% <<<------------------------------------------ liste_range ((N, L))---------------------------
% solver
% solver 1 : simple backtrack et colonnes dans l'ordre 1 2 .. N
/*
solve for
just print 1 st case
print all solutions
count all solutions
*/
solve_queens(N) :-
% 1° solution
solve_queens(N, _, true).
solve_queens(N, S) :-
solve_queens(N, S, true).
solve_queens(N, S, true) :-
% % solving queens for ...
writeln("... >>> solving queens for ..."),
write(N),
nl,
liste_range(N, L1),
reverse(L1, L),
solve_queens_2(L, N, [], S),
% say for . N . found (board (S))
% [say for . N . found (board (S))
write_info([[for, N, found(board(S))]]),
!.
solve_queens(N, S, first) :-
% % solving queens for ...
writeln("... >>> solving queens for ..."),
liste_range(N, L1),
reverse(L1, L),
solve_queens_2(L, N, [], S),
!.
solve_queens(N, S, all, D) :-
% % print all queens solutions for ...
writeln("... >>> print all queens solutions for ..."),
write(N),
nl,
init_counter(counter),
liste_range(N, L1),
reverse(L1, L),
!,
(
solve_queens_2(L, N, [], S),
incr_counter(counter),
display_board(S, N),
nl,
fail
;
true
),
% prints result
val_counter(counter, D),
!,
write_info([found([D, solutions])]).
solve_queens(N, S, count, D) :-
% % counts the number of cases for
writeln("... >>> counts the number of cases for "),
write(N),
nl,
init_counter(counter),
liste_range(N, L1),
reverse(L1, L),
!,
(
solve_queens_2(L, N, [], S),
incr_counter(counter),
write('.'),
fail
;
true
),
% prints result
val_counter(counter, D),
!,
write_info([found([D, solutions, for, N, queens])]).
% solves by backtracking
/*
L ::= x1 . x2 . .... : Xi : numbers of columns
called initially with (L = [1, 2, ... N]
*/
% >>> ------------------------------------------ solve_queens_2 ( (+L, +N, +K, -Solution))---------------------------
% DOC
% prédicat solve_queens_2 ( (+L, +N, +K, -Solution))
% last line
% [], N, S
% S
solve_queens_2([], N, S, S) :-
!.
% any line
% L, N, S
% S2
solve_queens_2(L, N, S, S2) :-
% trace
% prendre un élément
member_reste(L, X, Reste),
% vérifier les diagonales
K1 is X + 1,
K2 is X -1,
diagonal_ok(S, K1, K2),
% continue la récursion
solve_queens_2(Reste, N, [X | S] , S2).
% <<<------------------------------------------ solve_queens_2 ( (+L, +N, +K, -Solution)) ---------------------------
% vérifier les diagonales
% >>> ------------------------------------------ diagonal_ok ( (Liste, X1, X2)) ---------------------------
% DOC
% prédicat diagonal_ok ( (Liste, X1, X2))
diagonal_ok([], _, _) :-
!.
diagonal_ok([X | L], K, K1) :-
(
(
X = K
;
X = K1
)
->
!,
fail
;
K2 is K + 1,
K3 is K1 -1,
diagonal_ok(L, K2, K3)
).
% <<<------------------------------------------ diagonal_ok ( (Liste, X1, X2))---------------------------
% linear solver for N
% solve in linear time for N not multiple of od nor 3
solve_queens_l(N):-
solve_queens_l(N, _, true),
!.
solve_queens_l(N, S):-
solve_queens_l(N, S, true),
!.
solve_queens_l(N, S, true) :-
solve_queens_l(N, S, P, 1),
write(S),
nl,
check_sol(S),
display_board(S, N),
nl.
solve_queens_l(N, S , P, K) :-
(
K > N
->
S = []
;
!,
X is 1 +(3 * K) mod N,
K1 is K + 1,
S =[X | S1],
solve_queens_l(N, S1, P, K1)
).
% check of solutions
check_sol(S) :-
check_sol(S, S1, S2, 0),
sort(S, So),
write("So = "),
write(So),
nl,
nl,
write("S = "),
write(S),
nl,
sort(S1, So1),
write("So1 = "),
write(So1),
nl,
write("S1 = "),
write(S1),
nl,
length(S1, N1),
length(So1, No1),
(
N1 = No1
->
!
;
write('ascending diagonal error'),
nl
),
sort(S2, So2),
write("So2 = "),
write(So2),
nl,
write("S2 = "),
write(S2),
nl,
length(S2, N2),
length(So2, No2),
(
N2 = No2
->
!
;
write('descending diagonal error'),
nl
).
check_sol([], [], [], K).
check_sol([A | L],[X | L1],[Y | L2], K) :-
X is A -K,
Y is A + K,
K1 is K +1,
check_sol(L, L1 , L2, K1).
% solver 2 : simple backtrack et colonnes dans l'ordre N/2, N/2 +-1 ..... N 1 (ou un autre ordre)
% prelever un élement et garder le reste
member_reste([X | L], X, L) :-
true.
member_reste([X | L], Y,[X | U]) :-
!,
member_reste(L, Y, U).
% tests
% >>> ================================== False =============================================
% <<< ================================== False =============================================
q11 :-
display_board([1, 2, 3], 3),
display_board( [2, 4, 1, 3], 4).
% >>> ================================== tests for only first solution =============================================
t4 :-
(
solve_queens(4, S, true),
write("solution(4, S) = "),
write(solution(4, S)),
nl,
fail
;
true
).
q2 :-
(
member(K, [3, 4, 8]),
write("K = "),
write(K),
nl,
solve_queens(K, S),
fail
;
true
).
q13 :-
L = [100, 200, 300],
(
member_reste(L, X, U),
write("q3(L, X, U) = "),
write(q3(L, X, U)),
nl,
fail
;
true
).
qs3 :-
(
solve_queens(3, S),
fail
;
true
).
qs4 :-
(
solve_queens(4, S),
fail
;
true
).
qs5 :-
(
solve_queens(5, S),
fail
;
true
).
qs6 :-
(
solve_queens(6, S),
fail
;
true
).
% <<< ================================== tests for only first solution =============================================
% >>> ================================== 8 queens =============================================
qs8 :-
(
solve_queens(8, S, all, D),
fail
;
true
).
qc8 :-
(
solve_queens(8, S, count, N),
write("N = "),
write(N),
nl,
fail
;
true
).
fs8 :-
solve_queens(8, S).
% compte le nombre de solutions
qf8 :-
K = 8,
qf(8).
% <<< ================================== 8 queens =============================================
% >>> ================================== 20 queens =============================================
qf20 :-
K = 20,
qf(20).
% <<< ================================== 20 queens =============================================
% >>> ================================== Counting solutions =============================================
% compte le nombre de solutions
qf(N) :-
(
solve_queens(N, S, count, N_sol),
write_info([found([N_sol, solutions, for, N, queens])]),
fail
;
true
).
q1(N) :-
(
solve_queens(N, S, true),
!,
true
),
% prints result
% say for . N . found (board (S))
% [say for . N . found (board (S))
write_info([[for, N, found(board(S))]]),
!.
q2(N) :-
init_counter(counter),
P = true,
solve_queens(N, S, true),
incr_counter_v(counter, C),
write("C = "),
write(C),
nl.
% solution avec algorithme linéaire
ql(N) :-
solve_queens_l(N).
% <<< ================================== Counting solutions =============================================
% tests unitaires prolog
% >>> ================================== False =============================================
% <<< ================================== False =============================================
q1 :-
liste_range(4, L),
write(L),
liste_range(8, L8),
write(L8).
q21 :-
(
L = [1, 2, 3],
write("L = "),
write(L),
nl,
iteritems(L, X, N),
write("iter(X, N) = "),
write(iter(X, N)),
nl,
fail
;
true
).
SOMMAIRE