Пролог Решение проблемы N ферзей с проверкой диагонали

Заявление об ограничении ответственности: матрица представлена ​​в виде списка, где номер - это строка, а индекс (1-8) - это номер столбца.

Я новичок в Prolog и пытаюсь найти решение следующей проблемы с учетом следующих рекомендаций:

Рекомендации

Мой код:

    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]).

введите описание изображения здесь


person jewelltaylor9430    schedule 05.12.2018    source источник
comment
В Prolog нет функции functions, как в checkD. Пролог не является процедурным или функциональным языком, но является логическим языком и имеет предикаты.   -  person Guy Coder    schedule 05.12.2018
comment
Я не могу поверить, что человек, который написал это описание Пролога, использовал слово function в описании проблемы. Где ты это взял?   -  person Guy Coder    schedule 05.12.2018
comment
Для вашего предиката diagonal вам нужны позиции Row и Col, чтобы проверить его. Для anti-diagonal пробовали ли вы использовать N+1-Row и Col?   -  person Guy Coder    schedule 05.12.2018
comment
Для антидиагонали вы также можете перевернуть матрицу (заменить строки столбцами), а затем проверить диагонали с предикатом, который вы написали ... Это сеятель, но он работает   -  person damianodamiano    schedule 05.12.2018
comment
@damianodamiano Проверка диагональных функций не работает. Любая идея, где я ошибся?   -  person jewelltaylor9430    schedule 05.12.2018
comment
@GuyCoder Матрица представлена ​​в виде списка, где номер - это строка, а индекс (1-8) - это номер столбца. Также извините за злоупотребление терминологией. Я должен был сказать сказуемое. Есть идеи, где я ошибаюсь?   -  person jewelltaylor9430    schedule 05.12.2018
comment
@GuyCoder Прежде всего, большое спасибо за вашу помощь! По какой-то причине мне кажется, что мой предикат checkD не работает, потому что всякий раз, когда я запускаю его с помощью checkDiagonals ([5,1,8,4,2,7,3,6]), которая должна быть хорошей доской, я получаю false. Я понимаю ваши комментарии по поводу антидиагонали, я просто хочу сначала убедиться, что у меня правильная диагональ.   -  person jewelltaylor9430    schedule 05.12.2018
comment
Это ваш курс?   -  person Guy Coder    schedule 05.12.2018
comment
@GuyCoder Общая логика программы не нарушена. Все, что я сделал, - это добавил предикат findValue, который принимает значение строки (Number Value) и значение столбца (List Index) и приравнивает его к третьему аргументу предиката dValue. Затем это значение dValue сравнивается с другими ферзями, чтобы убедиться, что никакие значения строки и столбца двух ферзей не прибавляются к одному и тому же числу. Я также добавлю это объяснение в исходный вопрос. Извините, я новичок в ТАК.   -  person jewelltaylor9430    schedule 05.12.2018
comment
Также вы заметите, что я удаляю свои комментарии, которые, как я знаю, вы прочитали и не представляют ценности для других. Вы должны сделать то же самое.   -  person Guy Coder    schedule 05.12.2018
comment
@GuyCoder Я изменил вхождения dvalue на DValue, но он по-прежнему возвращает false с вводом checkDiagonals ([5,1,8,4,2,7,3,6]). Я никогда в жизни так не разочаровывался в программировании, хахаха, я действительно ненавижу Prolog. Честно говоря, я не могу больше ни о чем от вас просить, вы очень помогли, я просто собираюсь взять на себя потерю на этом задании. Сначала я попробую добавить базовые базы, но потом я закончу с этим хахаха   -  person jewelltaylor9430    schedule 05.12.2018
comment
@GuyCoder Да, ты прав. Я хорошо разбираюсь в логике, но мне явно нужно лучше выучить Пролог. Профессор предоставил нам возможность изучать язык, и у меня возникли проблемы с поиском учебных пособий на YouTube или книг, чтобы научить меня основам. Есть ли у вас какие-либо предложения относительно того, где я могу относительно быстро освоить SWI-Prolog?   -  person jewelltaylor9430    schedule 05.12.2018
comment
Интересно: Проблема восьми ферзей   -  person Guy Coder    schedule 05.12.2018
comment
@GuyCoder Кажется, я не могу открыть этот файл из-за: Внешняя система предикатов: земля / 1 не очистила исключение: ошибка (exist_error (процедура, пролог: file_open_event / 1), context (system: $ c_call_prolog / 0, _72) )   -  person jewelltaylor9430    schedule 06.12.2018
comment
@GuyCoder Я добавил подробные комментарии, объясняющие программу и пример платы, которая будет работать. Можете ли вы быстро взглянуть на это, чтобы увидеть, стала ли проблема более очевидной сейчас? Проект должен быть сдан сегодня вечером, но стоит лишь небольшого процента, поэтому меня не волнует моя оценка. Это просто убивает меня, когда я не могу понять это, хахахаха   -  person jewelltaylor9430    schedule 06.12.2018
comment
@GuyCoder Ооо, я вижу, это определенно жизнеспособное решение проблемы, но не в соответствии с критериями задания. Мы обязаны использовать указанный в инструкции формат   -  person jewelltaylor9430    schedule 06.12.2018
comment
@GuyCode Да, я только что удалил это, поскольку смог понять это. Этот только что поставил меня в тупик, смеется. Надеюсь, кто-то еще в будущем сможет помочь мне с этим, но не похоже, что Prolog - вообще популярный язык, поэтому мне, возможно, придется столкнуться с реальностью, что это навсегда останется загадкой хахахахха   -  person jewelltaylor9430    schedule 06.12.2018
comment
@GuyCoder Я очень признателен за вашу помощь сегодня, я бы никогда не ожидал получить такую ​​большую помощь от одного человека. Мне любопытно, как бы вы это сделали. Я вообще не использую шаблоны проектирования в логическом программировании. Если моя логика не имеет для вас смысла, не стесняйтесь просто опубликуйте, как вы бы это сделали.   -  person jewelltaylor9430    schedule 06.12.2018


Ответы (1)


Это из Prolog Programming for Artificial Intelligence четвертого издания Ивана Братко (WorldCat)

стр. 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

Хотя этот код может выглядеть не так, как ваш, если вы знаете, как реорганизовать код пролога, а затем измените имена предикатов и имена переменных и поверните доску так, чтобы строки были столбцами, а столбцы были строками, вы увидите, что этот ответ совпадает с вашей идеей и кодом.

Вот вторая часть ответа.

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.

Попробуйте сделать это, если код не имеет смысла. Преобразуйте вызов предиката в операторы записи, чтобы увидеть, какие значения Prolog передает предикату. Тогда это иногда имеет смысл и временами меньше и быстрее, чем использование трассировки.

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.

Обратите внимание, что с удаленными ограничениями он не генерирует допустимые решения, но показывает генерацию значений для выполнения предиката, что я и хотел.

person Guy Coder    schedule 05.12.2018
comment
Комментарии не подлежат расширенному обсуждению; этот разговор был перешел в чат. - person Samuel Liew♦; 06.12.2018