首页 > 解决方案 > Prolog 棋子动作

问题描述

我正在使用 prolog 制作一个人工智能国际象棋游戏。我有这个板:

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

标签: prologchess

解决方案


不幸的是,“这些动作应该作为一个可能的动作列表返回”不是在 Prolog 中处理事情的有用方法。最好的方法是写一个位置和另一个位置之间的关系来表达一个合法的举动。这种关系应该列举可能的回溯移动,而不是作为一个列表。

我们将编写一个行为如下的关系:

?- 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坐标常数并移动任意非零数,最多向左或向右移动 7 个方格。X

另一个维度的移动基本相同:

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

推荐阅读