Prolog 了解解决皇后问题的精彩计划的提示

Prolog 了解解决皇后问题的精彩计划的提示,prolog,n-queens,Prolog,N Queens,在Sterling&Shapiro的序言艺术中,练习第14.1(v)节: 这是一个精彩的程序,共11行,它很快解决了在棋盘上定位皇后的问题。它很神奇:只有一个计数器、递归和越来越长越来越短的列表。一、 即使有trace的帮助,我也不明白。有人能给我解释一下吗?你是如何编写这样一个程序的?什么是逻辑/思维过程,导致从其他(好的标准解决方案)中导出此程序: 让我们先看看上面的谓词。这里我们通过调用queens(N,Qs)来解决N×N queens问题。正文length(Qs,N)中的第一个调用构造了

在Sterling&Shapiro的序言艺术中,练习第14.1(v)节:

这是一个精彩的程序,共11行,它很快解决了在棋盘上定位皇后的问题。它很神奇:只有一个计数器、递归和越来越长越来越短的列表。一、 即使有trace的帮助,我也不明白。有人能给我解释一下吗?你是如何编写这样一个程序的?什么是逻辑/思维过程,导致从其他(好的标准解决方案)中导出此程序:


让我们先看看上面的谓词。这里我们通过调用
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
做了两件事:

  • 它“展开”了一个ups
    [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||||)调用

    在这里,我们将无法将其放在第一列(因为它被queen
    1
    占据),无法将其放在第二列(上对角线由queen
    2
    占据),第三列(列由queen
    2
    占据,下对角线由queen
    1
    占据),以及最后一列(下对角线由皇后
    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))))