Prolog 了解解决皇后问题的精彩计划的提示
在Sterling&Shapiro的序言艺术中,练习第14.1(v)节: 这是一个精彩的程序,共11行,它很快解决了在棋盘上定位皇后的问题。它很神奇:只有一个计数器、递归和越来越长越来越短的列表。一、 即使有trace的帮助,我也不明白。有人能给我解释一下吗?你是如何编写这样一个程序的?什么是逻辑/思维过程,导致从其他(好的标准解决方案)中导出此程序:Prolog 了解解决皇后问题的精彩计划的提示,prolog,n-queens,Prolog,N Queens,在Sterling&Shapiro的序言艺术中,练习第14.1(v)节: 这是一个精彩的程序,共11行,它很快解决了在棋盘上定位皇后的问题。它很神奇:只有一个计数器、递归和越来越长越来越短的列表。一、 即使有trace的帮助,我也不明白。有人能给我解释一下吗?你是如何编写这样一个程序的?什么是逻辑/思维过程,导致从其他(好的标准解决方案)中导出此程序: 让我们先看看上面的谓词。这里我们通过调用queens(N,Qs)来解决N×N queens问题。正文length(Qs,N)中的第一个调用构造了
让我们先看看上面的谓词。这里我们通过调用
queens(N,Qs)
来解决N×N queens问题。正文length(Qs,N)
中的第一个调用构造了一个长度N
的变量列表。接下来,它用placequeens(N,Qs,u,u,u)
调用placequeens/4
。因此,它将两个自由变量传递给place_queens/4
。稍后,我们将通过取消定位来构造一个列表
首先递归调用place_queens/4
,直到I
的值为零,例如,如果我们为N=4
“展开”程序,我们得到:
place_queens(4, [Q1,Q2,Q3,Q4], UT, [D1,D2,D3,D4|DT]) :-
place_queens(3, [Q1,Q2,Q3,Q4], [U4|UT], [D2,D3,D4|DT]) :-
place_queens(2, [Q1,Q2,Q3,Q4], [U3,U4|UT], [D3,D4|DT]) :-
place_queens(1, [Q1,Q2,Q3,Q4], [U2,U3,U4|UT], [D4|DT]) :-
place_queens(0, [Q1,Q2,Q3,Q4], [U1,U2,U3,U4|UT], DT),
%% ---
place_queen(1, [Q1,Q2,Q3,Q4], [U2,U3,U4|UT], DT),
place_queen(2, [Q1,Q2,Q3,Q4], [U3,U4|UT], [D4|DT]),
place_queen(3, [Q1,Q2,Q3,Q4], [U4|UT], [D3,D4|DT]),
place_queen(4, [Q1,Q2,Q3,Q4], UT, [D2,D3,D4|DT]).
(以上不是Prolog代码,而是显示调用结构的图示。)
因此,place_queens
做了两件事:
[U1、U2、U3、U4|||||
和down[D1、D2、D3、D4||||]的列表;及
place\u queen
place\u queen
的任务是在列表的某个地方填写I
列。它总是得到整个皇后职位列表[Q1、Q2、Q3、Q4]
和部分升降列表。这些上升和下降表示沿上下方向移动的对角线
如果我们为给定的皇后位置填写一个值,我们也会为给定的升降列表标记该值,从而“声明”该皇后的这些对角线。如果我们做得好,这就足够了,因为如果另一个女王想要占据一个已经被宣称的对角线上的位置,它的目的是将该值附加到相应的对角线上,但它将失败,因为它的值与已经分配的值不同
让我们用一个例子来说明这一点。当我们调用第一个place_queen(1[Q1,Q2,Q3,Q4],[U2,U3,U4||||||||||],|
时,我们可以将其分配到第一个位置,这是基本情况,因此这会导致以下事实:
place_queen(1,[Q1,Q2,Q3,Q4],[U2,U3,U4|_], _D) :-
Q1 = 1,
U2 = 1,
_D = [1|_].
这意味着现在我们的[Q1,Q2,Q3,Q4]
看起来像[1,Q2,Q3,Q4]
,对于上对角线它看起来像[U1,U2,U3,U4 |]=[U1,1,U3,U4 |]
对于[D1,D2,D3,D4 |]=[D1,D2,D3,D4,1 |
现在我们的目标是分配下一个place_queen(2[1,Q2,Q3,Q4],[U3,U4|U3],[D4,1|U3])
。我们知道我们不能将该值分配给Q
列表的第一项,因为该值被1
占用,因此这意味着两个皇后拥有相同的列并相互攻击,因此这将不起作用
因此,我们执行递归,并在此弹出上下列表,因此:
place_queen(2, [1,Q2,Q3,Q4], [U3,U4|UT], [D4, 1|DT]) :-
place_queen(2, [Q2,Q3,Q4], [U4|UT], [1|DT]).
现在我们的目标是把第二行的皇后放在棋盘的第二列,但又有一个问题:正方形的对角线已经被皇后1
占据了,我们可以从down有[1 | |]
这一事实推导出来。所以我们必须再次执行递归,比如:
place_queen(2, [1,Q2,Q3,Q4], [U4|UT], [1|DT]) :-
place_queen(2, [Q3,Q4], UT, DT).
在这里我们可以安全地放置女王,在这里,没有任何列表被阻止。因此,当我们这样做时,列表现在看起来像[Q1,Q2,Q3,Q4]=[1,Q2,2,Q4]
,[U1,U2,U3,U4 | | |]=[U1,1,U3,U4,2 | | |]
和[D1,D2,D3,D4 | | | |]=/code>。如果我们看一下我们分配的董事会,对角线确实有意义:
\D5 \D6 \D7 \ D8\
+---+---+---+---+
/| Q | | | |
U2+---+---+---+---+
/| | | Q | |
U3+---+---+---+---+
/| | | | |
U4+---+---+---+---+
/| | | | |
+---+---+---+---+
U5 /U6 /U7 / U8/
因此,我们可以看到,第一位女王声称D5
和U2
,第二位女王声称D6
和U5
现在我们可以把第三个皇后放在棋盘上,或者至少我们可以试着这样做,这样我们就可以用place|u queen(3[1,Q2,2,Q4],[U4,2|||],[D3,D4,1,2||||)调用
在这里,我们将无法将其放在第一列(因为它被queen1
占据),无法将其放在第二列(上对角线由queen2
占据),第三列(列由queen2
占据,下对角线由queen1
占据),以及最后一列(下对角线由皇后2
)声明。最终我们用完了Q
列表,因此我们将不得不回顾上一次皇后的任务
现在我们继续放置第二个皇后,剩下的唯一选项是将其放置在最后一列:
\D5 \D6 \D7 \ D8\
+---+---+---+---+
/| Q | | | |
U2+---+---+---+---+
/| | | | Q |
U3+---+---+---+---+
/| | | | |
U4+---+---+---+---+
/| | | | |
+---+---+---+---+
U5 /U6 /U7 / U8/
在这种情况下,[Q1,Q2,Q3,Q4]=[1,Q2,Q3,2]
,[U1,U2,U3,U4 |]=[U1,1,U3,U4,U5,2 | |和[D1,D2,D3,D4 | |]=[D1,D2,D3,D3,D4,1,D6,2 124 | | | |现在的问题是把下一个女王(女王)放在哪里:
我们可以再次分配第三个皇后,因此我们现在用place|u皇后(3[1,Q2,Q3,2],[U4,U5,2 | | | |],[D3,D4,1,D6,2 | | |]
调用谓词。我们不能将该皇后分配到第一个位置,因为皇后1
占据了该列,因此我们递归地用place|u皇后(3[Q2,Q2,2],[U5,2],[D4,2]调用它
。在这里放置皇后是没有问题的,因为所有三个列表的头部都是自由变量。因此,我们设置了Q2=U5=D4=3
,从而获得以下板:
\D5 \D6 \D7 \ D8\
+---+---+---+---+
/| Q | | | |
U2+---+---+---+---+
/| | | | Q |
U3+---+---+---+---+
/| | Q | | |
U4+---+---+---+---+
/| | | | |
+---+---+---+---+
U5 /U6 /U7 / U8/
所以现在我们的列表看起来像[Q1,Q2,Q3,Q4]=[1,3,Q3,2]
,[U1,U2,U3,U4 | |]=[U1,1,U3,U4,3,2 | |和[D1,D2,D3,D4 | |]=[D1,D2,D3,3,3,1,D6,2 | | | | | | | | | | | | | | | | | | | | |
\D5 \D6 \D7 \ D8\
+---+---+---+---+
/| Q | | | |
U2+---+---+---+---+
/| | | | Q |
U3+---+---+---+---+
/| | | | |
U4+---+---+---+---+
/| | | | |
+---+---+---+---+
U5 /U6 /U7 / U8/
\D5 \D6 \D7 \ D8\
+---+---+---+---+
/| Q | | | |
U2+---+---+---+---+
/| | | | Q |
U3+---+---+---+---+
/| | Q | | |
U4+---+---+---+---+
/| | | | |
+---+---+---+---+
U5 /U6 /U7 / U8/
\D5 \D6 \D7 \ D8\
+---+---+---+---+
/| Q | | | |
U2+---+---+---+---+
/| | | | Q |
U3+---+---+---+---+
/| | Q | | |
U4+---+---+---+---+
/| | | Q | |
+---+---+---+---+
U5 /U6 /U7 / U8/
\D5 \D6 \D7 \ D8\
+---+---+---+---+
/| | Q | | |
U2+---+---+---+---+
/| | | | Q |
U3+---+---+---+---+
/| Q | | | |
U4+---+---+---+---+
/| | | Q | |
+---+---+---+---+
U5 /U6 /U7 / U8/
queens(N,Qs) :-
length(Qs,N),
place_queens(N,Qs,_,_).
place_queens(0,_Qs,_Ups,_Downs).
place_queens(I,Qs,Ups,[_|Downs]) :-
I > 0, I1 is I-1,
place_queens(I1,Qs,[_|Ups] ,Downs),
place_queen(I,Qs,Ups,Downs).
place_queen(Q,[Q|_],[Q|_],[Q|_]).
place_queen(Q,[_|Qs],[_|Ups],[_|Downs] ):-
place_queen(Q,Qs,Ups,Downs).
place_queen(Q,[Q|_],[Q|_],[Q|_]).
place_queen(Q,[Q|_],[Q|_],[Q|_]).
place_queen(Q,Rs,Ups,Downs) :-
Rs = [R_1|_],
Ups = [U_1|_],
Downs = [D_1|_],
Q = R_1, Q = U_1, Q = D_1
queens(N) :-
length(Qs,N),
format("N: ~w, Qs: ~w~n",[N,Qs]).
?- queens(4).
N: 4, Qs: [_6476,_6482,_6488,_6494]
true.
queens(N) :-
length(Qs,N),
place_queens(N,Qs,_,_).
place_queens(0,_Qs,_Ups,_Downs).
place_queens(I,Qs,Ups,[_|Downs]) :-
I > 0,
I1 is I-1,
place_queens(I1,Qs,[_|Ups] ,Downs),
format('I1: ~w, Qs: ~w, Ups: ~w, Downs: ~w~n',[I1,Qs,Ups,Downs]).
?- queens(4).
I1: 0, Qs: [_6474,_6480,_6486,_6492], Ups: [_6528,_6516,_6504|_6506], Downs: _6536
I1: 1, Qs: [_6474,_6480,_6486,_6492], Ups: [_6516,_6504|_6506], Downs: [_6534|_6536]
I1: 2, Qs: [_6474,_6480,_6486,_6492], Ups: [_6504|_6506], Downs: [_6522,_6534|_6536]
I1: 3, Qs: [_6474,_6480,_6486,_6492], Ups: _6506, Downs: [_6510,_6522,_6534|_6536]
true ;
false.
place_queen(Q,[_|Rs],[_|Ups],[_|Downs] ):-
place_queen(Q,Rs,Ups,Downs).
queens(N,Qs) :-
length(Qs,N),
place_queens(N,Qs,_,_).
place_queens(0,_Qs,_Ups,_Downs).
place_queens(I,Qs,Ups,[_|Downs]) :-
I > 0,
I1 is I-1,
place_queens(I1,Qs,[_|Ups] ,Downs),
format('Generate 1 - I: ~w, Qs: ~w, Ups: ~w, Downs: ~w~n',[I,Qs,Ups,Downs]),
place_queen(I,Qs,Ups,Downs),
format('Result -> I: ~w, Qs: ~w, Ups: ~w, Downs: ~w~n',[I,Qs,Ups,Downs]).
place_queen(Q,Rs,Ups,Downs) :-
Rs = [R_1|_],
Ups = [U_1|_],
Downs = [D_1|_],
format('Test - Q : ~w, R_1: ~w, U_1: ~w, D_1: ~w~n',[Q,R_1,U_1,D_1]),
(
Rs = [Q|_],
Ups = [Q|_],
Downs = [Q|_]
->
format('Test success~n')
;
format('Test failure~n'),
fail
).
place_queen(Q,[_|Qs],[_|Ups],[_|Downs] ):-
format('Generate 2 - Q: ~w, Qs: ~w, Ups: ~w, Downs: ~w~n',[Q,Qs,Ups,Downs]),
place_queen(Q,Qs,Ups,Downs).
?- queens(4,Qs).
Generate 1 - I: 1, Qs: [_6488,_6494,_6500,_6506], Ups: [_6542,_6530,_6518|_6520], Downs: _6550
Test - Q : 1, Q_1: _6488, U_1: _6542, D_1: _6596
Test success
Result -> I: 1, Qs: [1,_6494,_6500,_6506], Ups: [1,_6530,_6518|_6520], Downs: [1|_6598]
Generate 1 - I: 2, Qs: [1,_6494,_6500,_6506], Ups: [_6530,_6518|_6520], Downs: [_6548,1|_6598]
Test - Q : 2, Q_1: 1, U_1: _6530, D_1: _6548
Test failure
Generate 2 - Q: 2, Qs: [_6494,_6500,_6506], Ups: [_6518|_6520], Downs: [1|_6598]
Test - Q : 2, Q_1: _6494, U_1: _6518, D_1: 1
Test failure
Generate 2 - Q: 2, Qs: [_6500,_6506], Ups: _6520, Downs: _6598
Test - Q : 2, Q_1: _6500, U_1: _6746, D_1: _6752
Test success
Result -> I: 2, Qs: [1,_6494,2,_6506], Ups: [_6530,_6518,2|_6748], Downs: [_6548,1,2|_6754]
Generate 1 - I: 3, Qs: [1,_6494,2,_6506], Ups: [_6518,2|_6748], Downs: [_6536,_6548,1,2|_6754]
Test - Q : 3, Q_1: 1, U_1: _6518, D_1: _6536
Test failure
Generate 2 - Q: 3, Qs: [_6494,2,_6506], Ups: [2|_6748], Downs: [_6548,1,2|_6754]
Test - Q : 3, Q_1: _6494, U_1: 2, D_1: _6548
Test failure
Generate 2 - Q: 3, Qs: [2,_6506], Ups: _6748, Downs: [1,2|_6754]
Test - Q : 3, Q_1: 2, U_1: _6902, D_1: 1
Test failure
Generate 2 - Q: 3, Qs: [_6506], Ups: _6898, Downs: [2|_6754]
Test - Q : 3, Q_1: _6506, U_1: _6932, D_1: 2
Test failure
Generate 2 - Q: 3, Qs: [], Ups: _6928, Downs: _6754
Generate 2 - Q: 2, Qs: [_6506], Ups: _6742, Downs: _6748
Test - Q : 2, Q_1: _6506, U_1: _6782, D_1: _6788
Test success
Result -> I: 2, Qs: [1,_6494,_6500,2], Ups: [_6530,_6518,_6740,2|_6784], Downs: [_6548,1,_6746,2|_6790]
Generate 1 - I: 3, Qs: [1,_6494,_6500,2], Ups: [_6518,_6740,2|_6784], Downs: [_6536,_6548,1,_6746,2|_6790]
Test - Q : 3, Q_1: 1, U_1: _6518, D_1: _6536
Test failure
Generate 2 - Q: 3, Qs: [_6494,_6500,2], Ups: [_6740,2|_6784], Downs: [_6548,1,_6746,2|_6790]
Test - Q : 3, Q_1: _6494, U_1: _6740, D_1: _6548
Test success
Result -> I: 3, Qs: [1,3,_6500,2], Ups: [_6518,3,2|_6784], Downs: [_6536,3,1,_6746,2|_6790]
Generate 1 - I: 4, Qs: [1,3,_6500,2], Ups: [3,2|_6784], Downs: [_6524,_6536,3,1,_6746,2|_6790]
Test - Q : 4, Q_1: 1, U_1: 3, D_1: _6524
Test failure
Generate 2 - Q: 4, Qs: [3,_6500,2], Ups: [2|_6784], Downs: [_6536,3,1,_6746,2|_6790]
Test - Q : 4, Q_1: 3, U_1: 2, D_1: _6536
Test failure
Generate 2 - Q: 4, Qs: [_6500,2], Ups: _6784, Downs: [3,1,_6746,2|_6790]
Test - Q : 4, Q_1: _6500, U_1: _7070, D_1: 3
Test failure
Generate 2 - Q: 4, Qs: [2], Ups: _7066, Downs: [1,_6746,2|_6790]
Test - Q : 4, Q_1: 2, U_1: _7100, D_1: 1
Test failure
Generate 2 - Q: 4, Qs: [], Ups: _7096, Downs: [_6746,2|_6790]
Generate 2 - Q: 3, Qs: [_6500,2], Ups: [2|_6784], Downs: [1,_6746,2|_6790]
Test - Q : 3, Q_1: _6500, U_1: 2, D_1: 1
Test failure
Generate 2 - Q: 3, Qs: [2], Ups: _6784, Downs: [_6746,2|_6790]
Test - Q : 3, Q_1: 2, U_1: _6962, D_1: _6746
Test failure
Generate 2 - Q: 3, Qs: [], Ups: _6958, Downs: [2|_6790]
Generate 2 - Q: 2, Qs: [], Ups: _6778, Downs: _6784
Generate 2 - Q: 1, Qs: [_6494,_6500,_6506], Ups: [_6530,_6518|_6520], Downs: _6586
Test - Q : 1, Q_1: _6494, U_1: _6530, D_1: _6626
Test success
Result -> I: 1, Qs: [_6488,1,_6500,_6506], Ups: [_6542,1,_6518|_6520], Downs: [_6584,1|_6628]
Generate 1 - I: 2, Qs: [_6488,1,_6500,_6506], Ups: [1,_6518|_6520], Downs: [_6548,_6584,1|_6628]
Test - Q : 2, Q_1: _6488, U_1: 1, D_1: _6548
Test failure
Generate 2 - Q: 2, Qs: [1,_6500,_6506], Ups: [_6518|_6520], Downs: [_6584,1|_6628]
Test - Q : 2, Q_1: 1, U_1: _6518, D_1: _6584
Test failure
Generate 2 - Q: 2, Qs: [_6500,_6506], Ups: _6520, Downs: [1|_6628]
Test - Q : 2, Q_1: _6500, U_1: _6776, D_1: 1
Test failure
Generate 2 - Q: 2, Qs: [_6506], Ups: _6772, Downs: _6628
Test - Q : 2, Q_1: _6506, U_1: _6806, D_1: _6812
Test success
Result -> I: 2, Qs: [_6488,1,_6500,2], Ups: [1,_6518,_6770,2|_6808], Downs: [_6548,_6584,1,2|_6814]
Generate 1 - I: 3, Qs: [_6488,1,_6500,2], Ups: [_6518,_6770,2|_6808], Downs: [_6536,_6548,_6584,1,2|_6814]
Test - Q : 3, Q_1: _6488, U_1: _6518, D_1: _6536
Test success
Result -> I: 3, Qs: [3,1,_6500,2], Ups: [3,_6770,2|_6808], Downs: [3,_6548,_6584,1,2|_6814]
Generate 1 - I: 4, Qs: [3,1,_6500,2], Ups: [_6770,2|_6808], Downs: [_6524,3,_6548,_6584,1,2|_6814]
Test - Q : 4, Q_1: 3, U_1: _6770, D_1: _6524
Test failure
Generate 2 - Q: 4, Qs: [1,_6500,2], Ups: [2|_6808], Downs: [3,_6548,_6584,1,2|_6814]
Test - Q : 4, Q_1: 1, U_1: 2, D_1: 3
Test failure
Generate 2 - Q: 4, Qs: [_6500,2], Ups: _6808, Downs: [_6548,_6584,1,2|_6814]
Test - Q : 4, Q_1: _6500, U_1: _7070, D_1: _6548
Test success
Result -> I: 4, Qs: [3,1,4,2], Ups: [_6770,2,4|_7072], Downs: [_6524,3,4,_6584,1,2|_6814]
Qs = [3, 1, 4, 2] .
queens(N, Rows) :-
NDiag is 2*N-1,
functor(Rows, array, N), % create the "arrays"
functor(Ups, array, NDiag),
functor(Downs, array, NDiag),
place_queen(1, N, Rows, Ups, Downs).
place_queen(C, N, Rows, Ups, Downs) :-
( C>N ->
true
;
between(1, N, R),
arg(R, Rows, C), % place column C queen in row R
U is C-R+N, arg(U, Ups, C), % ... and up-diagonal C-R+N
D is C+R-1, arg(D, Downs, C), % ... and down-diagonal C+R-1
C1 is C+1,
place_queen(C1, N, Rows, Ups, Downs)
).
% -------- Meaning of Variables ------
% N, M ... Size of the board
% I, J ... Number of the row current queen is on
% Qs, L ... List of length N used to represent the solution
% Cs ... Column as a list of fields of length N
% Us ... Up-Diagonal as an open list of fields
% Ds ... Down-Diagonal as an open list of fields
queens(N,Qs):- gen_list(N,Qs), place_queens(N,Qs,_,_).
gen_list(0,[]).
gen_list(N,[_|L]):-
N>0, M is N-1,
gen_list(M,L).
place_queens(0,_,_,_).
place_queens(I,Cs,Us,[_|Ds]):-
I>0, J is I-1,
place_queens(J,Cs,[_|Us],Ds),
place_queen(I,Cs,Us,Ds).
% place_queen(Queen,Column,Updiagonal,Downdiagonal) places a single queen
place_queen(I,[I|_],[I|_],[I|_]).
place_queen(I,[_|Cs],[_|Us],[_|Ds]):-
place_queen(I,Cs,Us,Ds).
queens(N,Qs) :-
length(Qs,N),
place_queens(N,Qs,_).
place_queens(0,_,_).
place_queens(I,Qs,Ups) :-
I > 0,
I1 is I-1,
place_queens(I1,Qs,[_|Ups]),
place_queen(I,Qs,Ups).
place_queen(Q,[Q|_],[Q|_]).
place_queen(Q,[_|Qs],[_|Ups]):-
place_queen(Q,Qs,Ups).
?- queens(3,L).
L = [1, 2, 3];
L = [3, 1, 2]; % row 3/col 1 -- row 1/col 2 -- row 2/col 3
L = [2, 3, 1];
false
C1 C2 C3
| | | Row
+---+---+---+
U1| / | / | / |-- 1
+---+---+---+
U2| / | / | / |-- 2
+---+---+---+
U3| / | / | / |-- 3
+---+---+---+
U3 U4 U5
row_col_ups(1, [ 1,C2,C3], [ 1,U2,U3,U4,U5]). % row 1
row_col_ups(1, [C1, 1,C3], [U1, 1,U3,U4,U5]).
row_col_ups(1, [C1,C2, 1], [U1,U2, 1,U4,U5]).
row_col_ups(2, [ 2,C2,C3], [U1, 2,U3,U4,U5]). % row 2
row_col_ups(2, [C1, 2,C3], [U1,U2, 2,U4,U5]).
row_col_ups(2, [C1,C2, 2], [U1,U2,U3, 2,U5]).
row_col_ups(3, [ 3,C2,C3], [U1,U2, 3,U4,U5]). % row 3
row_col_ups(3, [C1, 3,C3], [U1,U2,U3, 3,U5]).
row_col_ups(3, [C1,C2, 3], [U1,U2,U3,U4, 3]).
% place_queen(Q,Cols,Ups)
% Q -> queen/row
% Cols -> list of colunms/queens
% Ups -> open list of up-diagonals/queens
place_queen(Q,[Q|_],[Q|_]).
place_queen(Q,[_|Qs],[_|Ups]):-
place_queen(Q,Qs,Ups).
member(X,[X|_]).
member(X,[_|L]):-
member(X,L).
?- member(3,[1,2,3]).
true.
?- member(X,[1,2]).
X = 1;
X = 2.
?- L=[1,2,X,4], member(3,L).
L = [1, 2, 3, 4],
X = 3
?- member(3,L).
L = [3|_1388];
L = [_1178, 3|_1186];
L = [_1178, _1184, 3|_1192];
?- Col=[C1,C2,C3], place_queen(3,Col,UPS).
Col = [3, C2, C3],
UPS = [3|_]
?- Col=[C1,C2,C3], place_queen(1,Col,UPS), UPS2=[U2|UPS], place_queen(2,Col,UPS2).
Col = [3, C2, 2],
UPS = [3, 2|_],
UPS2 = [U2, 3, 2|_]
?- Col=[C1,C2,C3], place_queen(3,Col,UPS), UPS2=[U2|UPS], place_queen(2,Col,UPS2), UPS3=[U1|UPS2], place_queen(1,Col,UPS3).
Col = [3, 1, 2],
UPS = [3, 2|_],
UPS2 = [1, 3, 2|_],
UPS3 = [U1, 1, 3, 2|_]
place_queens(0,_Qs,_Ups,_Downs). % usually pred(0,[],[],[]) for closed list
% but with open-lists we have the variables.
place_queens(I,Qs,Ups,[_|Downs]) :-
I > 0, I1 is I-1,
place_queens(I1,Qs,[_|Ups] ,Downs), % in next row/queen
place_queen(I,Qs,Ups,Downs). % for the up-diagonals we move the layer
% one field up.
% for the down-diagonals we move the layer
% one field down.
row_col_downs(1, [ 1,C2,C3], [D1,D2, 1,D4,D5]).
row_col_downs(1, [C1, 1,C3], [D1,D2,D3, 1,D5]).
row_col_downs(1, [C1,C2, 1], [D1,D2,D3,D4, 1]).
row_col_downs(2, [ 2,C2,C3], [D1, 2,D3,D4,D5]).
row_col_downs(2, [C1, 2,C3], [D1,D2, 2,D4,D5]).
row_col_downs(2, [C1,C2, 3], [D1,D2,D3, 2,D5]).
row_col_downs(3, [ 3,C2,C3], [ 3,D2,D3,D4,D5]).
row_col_downs(3, [C1, 3,C3], [D1, 3,D3,D4,D5]).
row_col_downs(3, [C1,C2, 3], [D1,D2, 3,D4,D5]).
% Pure version with successor function
queensp(N,Qs):- gen_listp(N,Qs), place_queensp(N,Qs,_,_).
gen_listp(0,[]).
gen_listp(s(N),[_|L]):-
gen_listp(N,L).
place_queensp(0,_,_,_).
place_queensp(s(I),Cs,Us,[_|Ds]):-
place_queensp(I,Cs,[_|Us],Ds),
place_queen(s(I),Cs,Us,Ds).
place_queen(I,[I|_],[I|_],[I|_]).
place_queen(I,[_|Cs],[_|Us],[_|Ds]):-
place_queen(I,Cs,Us,Ds).
?- queensp(Q,L).
L = [],
Q = 0 ;
L = [s(0)],
Q = s(0) ;
L = [s(s(s(0))), s(0), s(s(s(s(0)))), s(s(0))],
Q = s(s(s(s(0))))