#prolog #chess
Вопрос:
Я создаю шахматную игру с искусственным интеллектом, используя пролог. У меня есть эта доска:
Board = [piece(white, rook, 1, 1), piece(white, knight, 2, 1), piece(white, bishop, 3, 1), piece(white, queen, 4, 1), piece(white, king, 5, 1), piece(white, bishop, 6, 1), piece(white, knight, 7, 1), piece(white, rook, 8, 1), piece(white, pawn, 1, 2), piece(white, pawn, 2, 2), piece(white, pawn, 3, 2), piece(white, pawn, 4, 2), piece(white, pawn, 5, 2), piece(white, pawn, 6, 2), piece(white, pawn, 7, 2), piece(white, pawn, 8, 2), piece(black, rook, 1, 8), piece(black, knight, 2, 8), piece(black, bishop, 3, 8), piece(black, queen, 4, 8), piece(black, king, 5, 8), piece(black, bishop, 6, 8), piece(black, knight, 7, 8), piece(black, rook, 8, 8), piece(black, pawn, 1, 7), piece(black, pawn, 2, 7), piece(black, pawn, 3, 7), piece(black, pawn, 4, 7), piece(black, pawn, 5, 7), piece(black, pawn, 6, 7), piece(black, pawn, 7, 7), piece(black, pawn, 8, 7)]
Как вы можете видеть, доска представлена списком. Я пытаюсь создать предикат, который возвращает возможные ходы для данной фигуры на доске. Ходы должны быть возвращены в виде списка возможных ходов.
Я довольно легко сделал ходы пешкой, но застрял в ладье и возможных ходах слона (горизонтальный,вертикальный, диагональный), и я озадачен.
правка: вот ходы пешки:
in_boundaries(Col,Row):-
between(1,8,Col),
between(1,8,Row).
create_board(Board) :-
findall(Piece, initial(Piece), Board).
nonmember(X,[Y|Ys]):-
X=Y,
nonmember(X,Ys).
nonmember(_,[]).
%% Pawn possible moves
movement(Board,piece(white,pawn,Col,Row),piece(white,pawn,Col,NewRow)):-
NewRow is Row 1,
in_boundaries(Col,NewRow),
nonmember(piece(_,_,Col,NewRow),Board). %%Check if (Col,Row 1) is empty.
movement(Board,piece(black,pawn,Col,Row),piece(black,pawn,Col,NewRow)):-
NewRow is Row-1,
in_boundaries(Col,NewRow),
nonmember(piece(_,_,Col,NewRow),Board). %%Check if (Col,Row 1) is empty.
movement(Board,piece(white,pawn,Col,Row),piece(white,pawn,NewCol,NewRow)):-
NewCol is Col-1,
NewRow is Row 1,
in_boundaries(Col,NewRow),
member(piece(black,_,NewCol,NewRow),Board). %%Check if the pawn could eat in (Col-1,Row 1).
movement(Board,piece(white,pawn,Col,Row),piece(white,pawn,NewCol,NewRow)):-
NewCol is Col 1,
NewRow is Row 1,
in_boundaries(Col,NewRow),
member(piece(black,_,NewCol,NewRow),Board). %%Check if the pawn could eat in (Col 1,Row 1).
movement(Board,piece(black,pawn,Col,Row),piece(black,pawn,NewCol,NewRow)):-
NewCol is Col-1,
NewRow is Row-1,
in_boundaries(Col,NewRow),
member(piece(black,_,NewCol,NewRow),Board). %%Check if the pawn could eat in (Col-1,Row-1).
movement(Board,piece(black,pawn,Col,Row),piece(black,pawn,NewCol,NewRow)):-
NewCol is Col-1,
NewRow is Row-1,
in_boundaries(Col,NewRow),
member(piece(black,_,NewCol,NewRow),Board). %%Check if the pawn could eat in (Col 1,Row-1).
Ответ №1:
К сожалению, «ходы должны быть возвращены в виде списка возможных ходов» не является полезным способом подхода к вещам в Прологе. Лучший способ сделать это-написать связь между позицией и другой позицией, выражающей законный ход. Это отношение должно перечислять возможные шаги по возвращению, а не в виде списка.
Мы напишем отношение, которое ведет себя следующим образом:
?- piece_moved(piece(white, rook, 2, 7), Moved).
Moved = piece(white, rook, 1, 7) ;
Moved = piece(white, rook, 3, 7) ;
Moved = piece(white, rook, 4, 7) ;
Moved = piece(white, rook, 5, 7) ;
Moved = piece(white, rook, 6, 7) ;
Moved = piece(white, rook, 7, 7) ;
Moved = piece(white, rook, 8, 7) ;
Moved = piece(white, rook, 2, 1) ;
Moved = piece(white, rook, 2, 2) ;
Moved = piece(white, rook, 2, 3) ;
Moved = piece(white, rook, 2, 4) ;
Moved = piece(white, rook, 2, 5) ;
Moved = piece(white, rook, 2, 6) ;
Moved = piece(white, rook, 2, 8) ;
false.
Впоследствии, если вам действительно нужен список, вы можете получить его с помощью findall/3
:
?- findall(Moved, piece_moved(piece(white, rook, 2, 7), Moved), Moves).
Moves = [piece(white, rook, 1, 7), piece(white, rook, 3, 7), piece(white, rook, 4, 7), piece(white, rook, 5, 7), piece(white, rook, 6, 7), piece(white, rook, 7, 7), piece(white, rook, 8, 7), piece(white, rook, 2, 1), piece(..., ..., ..., ...)|...].
(Кстати, не помешало бы посмотреть, как вы реализовали свои пешечные ходы.)
Я буду использовать следующий предикат, чтобы помочь проверить, является ли перемещение допустимым:
valid(Coordinate) :-
between(1, 8, Coordinate).
Тогда перемещение ладьи по одному измерению является:
piece_moved(piece(Color, rook, X, Y), piece(Color, rook, X1, Y)) :-
between(-7, 7, DeltaX),
dif(DeltaX, 0),
X1 is X DeltaX,
valid(X1).
Это сохраняет постоянную Y
координату и перемещается X
на произвольное ненулевое число до 7 квадратов влево или вправо, пока результирующая позиция верна.
Движение по другому измерению в основном то же самое:
piece_moved(piece(Color, rook, X, Y), piece(Color, rook, X, Y1)) :-
between(-7, 7, DeltaY),
dif(DeltaY, 0),
Y1 is Y DeltaY,
valid(Y1).
Комментарии:
1. Разве это
select(Y, [1, 2, 3, 4, 5, 6, 7, 8], Choices), member(Y1, Choices)
не было бы более эффективным?2. Это выделяет промежуточный список для выражения по существу
dif(Y, Y1)
. Да, вы могли бы сделать это более эффективным для этой конкретной части, но я думаю, что подход с добавлением смещений к позиции проще для OP обобщить на другие части.