Здесь лучше использовать аккумулятор : переменная, которую вы обновляете посредством рекурсивных вызовов и, таким образом, содержат своего рода «память». Здесь аккумулятор может хранить список узлов, которые мы посетили. Чтобы перейти к новому узлу, этот узел должен , а не быть в списке.
Итак, мы определяем предикат move/4
вместо move/3
, с:
move(X,Y,Z) :-
move(X, Y, Z, [X]).
Теперь мы можем определить предикат move(S, D, Path, Visited)
, используя два правила:
- в случае, если
S
и D
совпадают, мы закончили, независимо от того, что является Visited
, мы объединяем Path
с [D]
; и
- в противном случае мы «дойдем» до другого узла
N
через предикат from_to/2
, убедитесь, что он не является членом Visited
, затем мы сделаем рекурсивный вызов, где мы добавляем S
к N
посещенным узлам. Мы добавляем X
к результату рекурсии Z
.
Как например:
move(S, S, [S], _).
move(S, D, [S|Z], Visited) :-
from_to(S, N),
\+ member(N, Visited),
move(N, D, Z, [N|Visited]).
Для вашего примера графика:
![graph representation](https://i.stack.imgur.com/bYOso.png)
затем генерирует:
?- move(a, d, Z).
Z = [a, b, c, d] ;
false.
?- move(a, D, Z).
D = a,
Z = [a] ;
D = b,
Z = [a, b] ;
D = c,
Z = [a, b, c] ;
D = d,
Z = [a, b, c, d] ;
false.
?- move(A, d, Z).
A = d,
Z = [d] ;
A = a,
Z = [a, b, c, d] ;
A = b,
Z = [b, c, d] ;
A = c,
Z = [c, d] ;
false.
?- move(A, D, Z).
A = D,
Z = [D] ;
A = a,
D = b,
Z = [a, b] ;
A = a,
D = c,
Z = [a, b, c] ;
A = a,
D = d,
Z = [a, b, c, d] ;
A = b,
D = c,
Z = [b, c] ;
A = b,
D = d,
Z = [b, c, d] ;
A = c,
D = d,
Z = [c, d] ;
A = d,
D = c,
Z = [d, c] ;
A = d,
D = b,
Z = [d, c, b] ;
A = c,
D = b,
Z = [c, b] ;
false.
Если узел не «связан с собой», как, например, у нас нет пути от a
до a
, например, мы можем реализовать move
как:
move(S, D, [S|Z], V) :-
from_to(S, N),
\+ member(N, V),
move2(N, D, Z, [N|V]).
move2(S, S, [S], _).
move2(N, D, [S|Z], V) :-
move(N, D, Z, V).