avihaiB
avihaiB

Reputation: 91

Prolog chess pieces movements

I am making an ai chess game while using prolog. I've got this board:

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

As you can see, the board represented by a list. I am trying to make a predicate that returns the possible moves for a given piece on the board. The moves should be returned as a list of possible moves. I made the pawn moves pretty easily, but I got stuck in the rook and bishop possible moves (horizontal,vertical, diagonal) and I am puzzled.

edit: here are the pawn moves:

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

Upvotes: 0

Views: 518

Answers (1)

Isabelle Newbie
Isabelle Newbie

Reputation: 9378

Unfortunately "the moves should be returned as a list of possible moves" is not a helpful way of approaching things in Prolog. The best way to do this is to write a relation between a position and another position expressing a legal move. This relation should enumerate possible moves on backtracking, not as a list.

We will write a relation that behaves like this:

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

Afterwards, if you really need a list, you can get one using 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(..., ..., ..., ...)|...].

(By the way, it wouldn't have hurt to see how you implemented your pawn moves.)

I will use the following predicate to help check whether a move is valid:

valid(Coordinate) :-
    between(1, 8, Coordinate).

A move of a rook along one dimension is then:

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

This holds the Y coordinate constant and moves X by an arbitrary non-zero number up to 7 squares left or right, as long as the resulting position is valid.

A move along the other dimension is basically the same:

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

Upvotes: 2

Related Questions