I am new in Prolog. I am trying to develop a Program which goal is, given the X,Y coordinate of a trophy (specified in the fact trofeo(4,3)), and the coordinates of some obstacles (specified in the fact ostacolo(,)), the Program has to find the shorthest path between the initial fixed coordinates(0,0) and the trophy, avoiding obstacles and without returning in visited coordinates.
For each rule you will find a comment explaining it. The main problem is that now, I am trying to generate all the possible paths.
The fact is that if I use only the move up and move right actions, (using only the rules X1 is X+1, Y1 is Y
and X1 is X, Y1 is Y+1
), and without using the rule about the visited position, so without the line: ( \+(visitato(X1,Y1))-> assert(visitato(X1, Y1)))
,
the program gives as output all the possible paths.(For example,in the simple case here, it will return Paths = [[(0, 0), (0, 1), (1, 1)], [(0, 0), (1, 0), (1, 1)]].)
While if I add all the possible actions, and the rule:
(\+(visitato(X1,Y1))-> assert(visitato(X1, Y1))),
the program find only one of the paths, for example gives as an output only: Paths = [[(0, 0), (1, 0), (0, 0), (0, 1), (1, 1)]]
. (it shows the right coordinates, but (0,0) twice, because is not assterted as visited and all in one path).
Thanks in advance to everyone.
% to calculate the max
max([X],X):-!.
max([X|T],X):- max(T,N),X>=N,!.
max([X|T],N):- max(T,N).
:- dynamic visitato/2.
ostacolo(2,0).
trofeo(1,1).
% with this I am finding the maximum X and Y value between obstacles and trophy, to set a limit in the "grid".
max_coordinate(MaxX, MaxY) :-
findall(X, ostacolo(X, _), XOstacoli),
findall(Y, ostacolo(_, Y), YOstacoli),
findall(X, trofeo(X, _), XTesoro),
findall(Y, trofeo(_, Y), YTesoro),
append(XTesoro, XOstacoli, ListaX),
append(YTesoro, YOstacoli, ListaY),
max(ListaX,MaxX),
max(ListaY,MaxY).
%every X,Y respects the limit if they are lower or equal to the maximum X and Y calculated before
limite(X, Y) :-
max_coordinate(MaxX, MaxY),
X =< MaxX,
Y =< MaxY.
% base case for recursion
path((X,Y), (X,Y), [(X,Y)], _ ).
% Limit is a constant to not exceed the Stack limit, adiacente is the rule written below
path((X,Y), Trofeo, [(X,Y)|Path], Limit) :-
Limit > 0,
adiacente((X,Y), (X1,Y1)),
NewLimit is Limit - 1,
path((X1,Y1), Trofeo, Path,NewLimit).
% I recall in the console ?- trofeo(X,Y), find_all_paths((0,0),(X,Y), Paths), to search for the paths
find_all_paths(Start, Trofeo, Paths) :-
setof(Path, path(Start, Trofeo, Path, 20), Paths).
% basically with this we are saying that there are four possible actions: move up, right, left, down. The coordinates evaluated must be positive(rule positivo), respect the limit(rule limite), must be not an obstacle(rule \+obstacle), and if they are not yet visited(rule \+(visitato(X1,Y1)), then we will insert a fact, that will state that the current X1,Y1 coordinate was visited.
adjacent((X, Y), (X1, Y1)) :-
(X1 is X, Y1 is Y - 1),
positivo(X1,Y1),
limite(X1,Y1),
\+ostacolo(X1,Y1),
( \+(visitato(X1,Y1))-> assert(visitato(X1, Y1))).
adjacent((X, Y), (X1, Y1)) :-
(X1 is X-1, Y1 is Y),
positivo(X1,Y1),
limite(X1,Y1),
\+ostacolo(X1,Y1),
( \+(visitato(X1,Y1))-> assert(visitato(X1, Y1))).
adjacent((X, Y), (X1, Y1)) :-
(X1 is X + 1, Y1 is Y),
positivo(X1,Y1),
limite(X1,Y1),
\+ostacolo(X1,Y1),
( \+(visitato(X1,Y1))-> assert(visitato(X1, Y1))).
adjacent((X, Y), (X1, Y1)) :-
(X1 is X, Y1 is Y + 1),
positivo(X1,Y1),
limite(X1,Y1),
\+ostacolo(X1,Y1),
( \+(visitato(X1,Y1))-> assert(visitato(X1, Y1))).
% establish that all the coordinates must be positive
positivo(X,Y) :-
X >= 0, Y >= 0.