Как использовать динамические списки в рекурсивной функции на Прологе

У меня есть динамический список, в котором хранится координата поля и владелец этого поля.

:-dynamic
    board/2.

Одна запись в этом списке выглядит так:

board(e4,[w]).

Есть еще 22 позиции на доске, все похожие.

Я пытаюсь реализовать ИИ для игры, для которой предназначена доска. Я использую альфа-бета-алгоритм и поэтому должен создавать новые «доски» для оценки ситуации.

У меня есть копия оригинальной доски для работы, но теперь у меня есть функция настройки доски для текущего хода, например:

move(position,boardOld,boardNew)

Это называется рекурсивным, поэтому во втором вызове boardOld равняется boardNew, а boardNew — это oldBoard со следующим шагом в анализе.

Моя идея состояла в том, чтобы копировать старую плату в каждой итерации, но я понятия не имею, как это сделать, поскольку это

copy_predicate_clauses(boardOld(A,B),boardNew(A,B)).

добавит старую доску к новой доске, потому что список уже существует.

Я использую следующий алгоритм (не могу его скопировать, так как это изображение):

http://www.cuceinetwork.net/archivos/prolog/The_Art_of_Prolog.pdf

Страница PDF 445 (страница книги 407).

Алгоритм получает позицию как «доску» при инициализации, я не знаю, как это сделать с моим списком, и, кроме того, предложение move(Move,Position,Position1) возвращает новую доску с текущим ходом. Это называется рекурсивным, и я понятия не имею, как создать доску для позиции 1, не перезаписывая те, что были раньше.

Редактировать//

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

findall((X,Y),board(X,Y),CurrentBoard).

CurrentBoard дает мне такой список

[(e4,[w,w]),(g4,[s,w]),(b7,[r,w,s])]

Теперь я не могу использовать свои методы для определения возможных ходов.

У меня есть такие факты, как

move(e4,d5).
move(d5,e6).

указав, какой ход (от, до) возможен, и теперь я попробовал это

findall((X,Y),listMoves(CurrentBoard,X,Y),possibleMoves).

с чем-то вроде этого. Я борюсь в этот момент. Как создать список с возможными ходами. Мне каким-то образом нужно получить координату X из currentBoard, проверить, принадлежит ли мне глава списка из этой координаты (пешки на этой координате), и проверить, свободна ли координата Y (до).

listMoves([Coordinate|[Head|Tail]], X, Y) :-
     move(X,Y),
     ownField(X,Coordinate,Head),

person Sven182    schedule 13.01.2016    source источник
comment
На это очень сложно (если не невозможно) ответить, учитывая отсутствие подробностей.   -  person Scott Hunter    schedule 13.01.2016
comment
Я отредактирую вопрос и поделюсь более подробной информацией   -  person Sven182    schedule 13.01.2016
comment
Ваша проблема в том, что вы пытаетесь рассматривать динамическое хранилище как список (вы сами так говорите, но board/2 — это предикат, а не список), и он не подходит для этой цели. Вам лучше создать явные списки для состояния вашей доски и передать их всем, потому что манипулировать фактическими списками намного проще, чем манипулировать фактами в динамическом хранилище.   -  person Daniel Lyons    schedule 14.01.2016
comment
Я отредактировал свою тему с некоторыми мыслями ... Но снова борюсь   -  person Sven182    schedule 14.01.2016
comment
possibleMoves - это атом, а не переменная в Прологе. :)   -  person Daniel Lyons    schedule 14.01.2016
comment
Кроме того, [Coordinate|[Head|Tail]] эквивалентно [Coordinate,Head|Tail], что, вероятно, не то, что вам нужно. На самом деле это может помочь проиллюстрировать, почему неразумно использовать ,/2, как если бы в Прологе были пары; вы можете слишком легко запутаться.   -  person Daniel Lyons    schedule 14.01.2016
comment
IMO, вы попадаете на правильный путь, хотя я думаю, что если вы соедините половину своего кода с прохождением доски, а не другую половину, вы только создадите себе новые проблемы в будущем. Ключ в том, чтобы передать состояние доски чему-то, чтобы генерировать возможные ходы. Затем вы можете выбрать один и использовать его для создания нового состояния доски.   -  person Daniel Lyons    schedule 14.01.2016
comment
Но мне как-то приходится использовать пары? Я не совсем уверен, понимаю ли я вашу идею, как определить возможные ходы... не могу ли я использовать свой CurrentBoard и извлечь их? У вас есть идея, как генерировать ходы от X до Y с цветом пешки w? Я думаю, что не понимаю вашей идеи, как это сделать ... довольно поздно в Европе, завтра уже проверю ответы ... спасибо, хотя   -  person Sven182    schedule 14.01.2016


Ответы (1)


Если вы читаете (распечатанную) страницу 401, авторы обрисовывают основной алгоритм игрового процесса следующим образом:

   play(Game) :-
         initialize(Game, Position, Player),
         display_game(Position, Player),
         play(Position, Player, Result).

В остальной части раздела термин «позиция» используется таким образом, что мне кажется, что они имеют в виду все состояние игры. Для такой игры, как шахматы, это будет состояние самой доски: где какие фигуры.

Далее авторы обсуждают move/2 и move/3, которые определяются следующим образом:

Удобно отделить выбор хода на choose_move/3 от его выполнения на move/3

А затем позже на странице 403,

Предикат move(Position, Move) истинен, если Move является возможным ходом из текущей позиции.

В совокупности все это говорит мне о том, что они ожидают, что Position будет полной шахматной доской (я думаю, вы играете в шахматы, не так ли?), а Move будет законным ходом для целей определения move/2, а затем move/3 это просто move/2, возвращающее результирующую доску. Другими словами, исходная шахматная доска может выглядеть примерно так:

starting_board([[b-r, b-b, b-n, b-q, b-k, b-n, b-b, b-r],
                [b-p, b-p, b-p, b-p, b-p, b-p, b-p, b-p],
                [nil, nil, nil, nil, nil, nil, nil, nil],
                [nil, nil, nil, nil, nil, nil, nil, nil],
                [nil, nil, nil, nil, nil, nil, nil, nil],
                [nil, nil, nil, nil, nil, nil, nil, nil],
                [w-p, w-p, w-p, w-p, w-p, w-p, w-p, w-p],
                [w-r, w-b, w-n, w-q, w-k, w-n, w-b, w-r]]).    

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

Отсюда вы готовы написать move/2 и move/3. Я был бы склонен (в дидактических целях) просто написать move/3 и использовать его для построения move/2, но для эффективности вы, вероятно, захотите сделать их отдельно. Я достаточно плохо играю в шахматы, поэтому я собираюсь остановиться на этом (и я все равно не уверен, что вы занимаетесь шахматами). Но, по сути, вы хотите увидеть, что move(StartPosition, Move, NewPosition), учитывая начальную позицию, объединит Move с каким-то кратким описанием хода и NewPosition со всем состоянием доски после того, как вы сделали этот ход, так что вы получите до-и- после снимка.

После того, как вы создали эти части, я думаю, вы можете в основном использовать код книги как есть.

Я думаю, что у вас в основном было несколько недоразумений:

  1. Доска не является предикатом с несколькими решениями. Это структура данных, которую вы создаете, которая представляет всю историю того, что происходит.
  2. Динамические предикаты не формируют список. Это правда, что у вас может быть несколько решений и что они имеют порядок, это не удобная структура данных для тех манипуляций, которые вам нужно будет выполнить.
  3. Я действительно не думаю, что вы хотите смешать эти две идеи вместе и посмотреть, что получится.
person Daniel Lyons    schedule 14.01.2016