Reputation: 91
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
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