N Queens问题检查对角线的序言解决方案

时间:2018-12-05 05:51:28

标签: prolog n-queens

免责声明:矩阵表示为列表,其中数字是行,索引(1-8)是列号。

我是Prolog的新手,并根据以下指南尝试解决以下问题:

Guidelines

我的代码:

    eightQueens(Board) :-
        permutation([1,2,3,4,5,6,7,8], Board),
        checkDiagonals(Board).

    /* Check Diagonal and AntiDiagonal (Diagonal not implemented yet) 
        checkD checks antidiagonal */
    checkDiagonals([H|T]) :-
        checkD([H|T]).

    /* Value is the index of H so it acts as the column value.
       dValue is the sum of H, which represents row value, and Value.
       If any two queens have the same dValue this means they are in 
       the same anti-diagonal.
       checkD gets the dValue of the first element in the list and 
       passes it to checkDHelper which compares the dValue against 
       the dValue's of the other elements in the list. */
    checkD([]).
    checkD([H|T]) :-
        indexOf([H|T], H, RowValue),
        findValue(RowValue, H, DValue),
        checkDHelper(T, DValue),
        checkD(T).

    /* checkDHelper compares the dValue against 
       the dValue's of the other elements in the list. */ 

    checkDHelper([], DValue). 
    checkDHelper([H|T], DValue) :-
        indexOf([H|T], H, RowValueIndex),
        findValue(IndexValue, H, DValueIndex),
        %check if dValue of current index is equal to Value provided
        notEqual(DValue, DValueIndex),
        checkDHelper(T, DValue).

     %Finds index of the element
    indexOf([Element|_], Element, 1).
    indexOf([_|Tail], Element, Value) :-
         indexOf(Tail, Element, Value1),
         Value is Value1 + 1.

    %Checks if values are not equal 
    notEqual(X, Y) :-
        X =\= Y.

    %Finds dValue
    findValue(RowValue, ColumnValue, dValue) :-
        dValue is X + Y.

下面是一个可以正常工作的板的示例(表示为checkDiagonals([5,1,8,4,2,7,3,6])。)

enter image description here

1 个答案:

答案 0 :(得分:1)

这摘自Ivan Bratko(WorldCat)的Prolog Programming for Artificial Intelligence第四版

第111页-图4.12八皇后问题的程序2。

solution(Queens) :-
    permutation([1,2,3,4,5,6,7,8], Queens),
    safe(Queens).

% safe(Queens): Queens is a list of Y-coordinates of non-attacking queens

safe([]).

safe([Queen|Others]) :-
    safe(Others),
    noattack(Queen,Others,1).

% noattack(Queen, Queens, Dist):
%   Queen does not attack any queen in Queens at horizontal distance Dist

noattack(_,[],_).
noattack(Y,[Y1|Ylist],Xdist) :-
    Y1 - Y =\= Xdist,            % Not upward diagonal attack
    Y - Y1 =\= Xdist,            % Not downward diagonal attack
    Dist1 is Xdist + 1,
    noattack(Y,Ylist,Dist1).

示例运行。

solution(Queens).
Queens = [1, 5, 8, 6, 3, 7, 2, 4] ;
Queens = [1, 6, 8, 3, 7, 4, 2, 5] ;
Queens = [1, 7, 4, 6, 8, 2, 5, 3] ;
Queens = [1, 7, 5, 8, 2, 4, 6, 3] ;
Queens = [2, 4, 6, 8, 3, 1, 7, 5] ;
Queens = [2, 5, 7, 1, 3, 8, 6, 4] ;
Queens = [2, 5, 7, 4, 1, 8, 6, 3] ;
Queens = [2, 6, 1, 7, 4, 8, 3, 5] ;
Queens = [2, 6, 8, 3, 1, 4, 7, 5] ;
Queens = [2, 7, 3, 6, 8, 5, 1, 4] ;
Queens = [2, 7, 5, 8, 1, 4, 6, 3] ;
Queens = [2, 8, 6, 1, 3, 5, 7, 4] ;
Queens = [3, 1, 7, 5, 8, 2, 4, 6] ;
Queens = [3, 5, 2, 8, 1, 7, 4, 6] ;
Queens = [3, 5, 2, 8, 6, 4, 7, 1] ;
Queens = [3, 5, 7, 1, 4, 2, 8, 6] ;
Queens = [3, 5, 8, 4, 1, 7, 2, 6] ;
Queens = [3, 6, 2, 5, 8, 1, 7, 4] 
Action (h for help) ? abort

如果您知道如何refactor Prolog代码,然后更改谓词名称和变量名称,并旋转木板,使行为列,列为行,则此代码可能与您的代码看起来不同,您将看到此答案与您的想法和代码相同。

这是答案的第二部分。

solution_2(N,Queens) :-
    numlist(1,N,List),
    permutation(List, Queens),
    safe(Queens).

示例运行。

?- solution_2(1,Queens).
Queens = [1] ;
false.

?- solution_2(2,Queens).
false.

?- solution_2(3,Queens).
false.

?- solution_2(4,Queens).
Queens = [2, 4, 1, 3] ;
Queens = [3, 1, 4, 2] ;
false.

?- solution_2(5,Queens).
Queens = [1, 3, 5, 2, 4] ;
Queens = [1, 4, 2, 5, 3] ;
Queens = [2, 4, 1, 3, 5] ;
Queens = [2, 5, 3, 1, 4] ;
Queens = [3, 1, 4, 2, 5] ;
Queens = [3, 5, 2, 4, 1] ;
Queens = [4, 1, 3, 5, 2] ;
Queens = [4, 2, 5, 3, 1] ;
Queens = [5, 2, 4, 1, 3] ;
Queens = [5, 3, 1, 4, 2] ;
false.

?- solution_2(6,Queens).
Queens = [2, 4, 6, 1, 3, 5] ;
Queens = [3, 6, 2, 5, 1, 4] ;
Queens = [4, 1, 5, 2, 6, 3] ;
Queens = [5, 3, 1, 6, 4, 2] ;
false.

?- solution_2(7,Queens).
Queens = [1, 3, 5, 7, 2, 4, 6] ;
Queens = [1, 4, 7, 3, 6, 2, 5] ;
Queens = [1, 5, 2, 6, 3, 7, 4] ;
Queens = [1, 6, 4, 2, 7, 5, 3] ;
Queens = [2, 4, 1, 7, 5, 3, 6] ;
Queens = [2, 4, 6, 1, 3, 5, 7] ;
Queens = [2, 5, 1, 4, 7, 3, 6] ;
Queens = [2, 5, 3, 1, 7, 4, 6] ;
Queens = [2, 5, 7, 4, 1, 3, 6] ;
Queens = [2, 6, 3, 7, 4, 1, 5] ;
Queens = [2, 7, 5, 3, 1, 6, 4] ;
Queens = [3, 1, 6, 2, 5, 7, 4] ;
Queens = [3, 1, 6, 4, 2, 7, 5] ;
Queens = [3, 5, 7, 2, 4, 6, 1] ;
Queens = [3, 6, 2, 5, 1, 4, 7] ;
Queens = [3, 7, 2, 4, 6, 1, 5] ;
Queens = [3, 7, 4, 1, 5, 2, 6] ;
Queens = [4, 1, 3, 6, 2, 7, 5] ;
Queens = [4, 1, 5, 2, 6, 3, 7] ;
Queens = [4, 2, 7, 5, 3, 1, 6] ;
Queens = [4, 6, 1, 3, 5, 7, 2] ;
Queens = [4, 7, 3, 6, 2, 5, 1] ;
Queens = [4, 7, 5, 2, 6, 1, 3] ;
Queens = [5, 1, 4, 7, 3, 6, 2] ;
Queens = [5, 1, 6, 4, 2, 7, 3] ;
Queens = [5, 2, 6, 3, 7, 4, 1] ;
Queens = [5, 3, 1, 6, 4, 2, 7] ;
Queens = [5, 7, 2, 4, 6, 1, 3] ;
Queens = [5, 7, 2, 6, 3, 1, 4] ;
Queens = [6, 1, 3, 5, 7, 2, 4] ;
Queens = [6, 2, 5, 1, 4, 7, 3] ;
Queens = [6, 3, 1, 4, 7, 5, 2] ;
Queens = [6, 3, 5, 7, 1, 4, 2] ;
Queens = [6, 3, 7, 4, 1, 5, 2] ;
Queens = [6, 4, 2, 7, 5, 3, 1] ;
Queens = [6, 4, 7, 1, 3, 5, 2] ;
Queens = [7, 2, 4, 6, 1, 3, 5] ;
Queens = [7, 3, 6, 2, 5, 1, 4] ;
Queens = [7, 4, 1, 5, 2, 6, 3] ;
Queens = [7, 5, 3, 1, 6, 4, 2] ;
false.

编辑

来自评论The logic Bratko is using does not make sense to me.

如果代码没有意义,请尝试执行此操作。将对谓词的调用隐藏到write语句中,以查看Prolog向谓词提供的值。然后,有时它比有时使用trace有意义,并且更小,更快。

solution_3(N,Queens) :-
    numlist(1,N,List),
    permutation(List, Queens),
    safe_3(Queens).

safe_3([]).

safe_3([Queen|Others]) :-
    safe_3(Others),
    noattack_3(Queen,Others,1).

noattack_3(_,[],_).
noattack_3(Y,[Y1|Ylist],Xdist) :-
    write('noattack_3 - Y:'),write(Y),write(', Y1: '),write(Y1),write(', Ylist: '),write(Ylist),write(', Xdist: '),writeln(Xdist),
    Dist1 is Xdist + 1,
    noattack_3(Y,Ylist,Dist1).

以3x3的木板运行可以得到:

?- solution_3(3,Queens).
noattack_3 - Y:2, Y1: 3, Ylist: [], Xdist: 1
noattack_3 - Y:1, Y1: 2, Ylist: [3], Xdist: 1
noattack_3 - Y:1, Y1: 3, Ylist: [], Xdist: 2
Queens = [1, 2, 3] ;
noattack_3 - Y:3, Y1: 2, Ylist: [], Xdist: 1
noattack_3 - Y:1, Y1: 3, Ylist: [2], Xdist: 1
noattack_3 - Y:1, Y1: 2, Ylist: [], Xdist: 2
Queens = [1, 3, 2] ;
noattack_3 - Y:1, Y1: 3, Ylist: [], Xdist: 1
noattack_3 - Y:2, Y1: 1, Ylist: [3], Xdist: 1
noattack_3 - Y:2, Y1: 3, Ylist: [], Xdist: 2
Queens = [2, 1, 3] ;
noattack_3 - Y:3, Y1: 1, Ylist: [], Xdist: 1
noattack_3 - Y:2, Y1: 3, Ylist: [1], Xdist: 1
noattack_3 - Y:2, Y1: 1, Ylist: [], Xdist: 2
Queens = [2, 3, 1] ;
noattack_3 - Y:1, Y1: 2, Ylist: [], Xdist: 1
noattack_3 - Y:3, Y1: 1, Ylist: [2], Xdist: 1
noattack_3 - Y:3, Y1: 2, Ylist: [], Xdist: 2
Queens = [3, 1, 2] ;
noattack_3 - Y:2, Y1: 1, Ylist: [], Xdist: 1
noattack_3 - Y:3, Y1: 2, Ylist: [1], Xdist: 1
noattack_3 - Y:3, Y1: 1, Ylist: [], Xdist: 2
Queens = [3, 2, 1] ;
false.

请注意,除去约束后,它并没有生成有效的解决方案,而是显示了谓词执行值的生成,这正是我想要的。