The problem is that you don't bookkeep where you've already been. Now say you are looking to go from sasktchewan
to manitoba
. Prolog will evaluate this as:
(sasktchewan) <--------------
`--(alberta) \
`--(british_columbia) |
|--(yukon) fail! |
`--(nwt) |
`-(sasktchewan)---/
Now since you don't tell prolog you can't going in loops, it will keep appending (sasktchewan) -> (alberta) -> (nwt)
to the path and never find the aimed target.
Demo:
?- route(sasktchewan,manitoba,L).
L = [go(sasktchewan, alberta), go(alberta, saskatchewan), go(saskatchewan, manitoba)] ;
L = [go(sasktchewan, alberta), go(alberta, saskatchewan), go(saskatchewan, manitoba), go(manitoba, nwt), go(nwt, manitoba)] ;
L = [go(sasktchewan, alberta), go(alberta, saskatchewan), go(saskatchewan, nwt), go(nwt, manitoba)] ;
L = [go(sasktchewan, alberta), go(alberta, nwt), go(nwt, manitoba)] ;
L = [go(sasktchewan, alberta), go(alberta, nwt), go(nwt, saskatchewan), go(saskatchewan, manitoba)] ;
L = [go(sasktchewan, alberta), go(alberta, nwt), go(nwt, manitoba), go(manitoba, saskatchewan), go(saskatchewan, manitoba)] ;
What you need to do is use an accumulator that lists all the places where you've already been. Each time you do a member-check from the moment you've already visited that city, you break. Thus:
%We start a route with being in city A
route(A, B, L) :-
route(A, B,[A], L).
%In case we find a city with a border, don't hesitate and go to the city!
route( A, B,_,[go(A,B)]) :-
borders(A,B).
%Too bad, now looking for an extra city
route(A,B,Been,[go(A,Z)|ZtoB]) :-
borders(A,Z), %hahaa, we can access city Z
\+ member(Z,Been), %hold on! Did we already visit Z. No! we didn't
route(Z,B,[Z|Been],ZtoB). %Log city Z and look for a root from Z to B
This is not optimal: once a visit to city a failed at one path, it will also fail if you took another path to that city. You can use the non-bactrackable store to maintain a list of cities that you've visited in order to convert it to an O(n2) algorithm. The implementation depends on the dialect.