Используя этот вариант, можно вызвать hanoi(3,left,middle,right,Moves-NMoves)
, и список ходов будет создан до Moves
, а количество выполненных ходов будет установлено до NMoves
.Можно легко написать предикат для форматирования каждого элемента списка во ввод / вывод.
Обратите внимание, как здесь используются списки различий, чтобы избежать дорогостоящего использования append/3
.Вызов length/2
в предикате hanoi/5
служит своего рода доказательством того, что результирующий список ходов имеет правильный размер.
hanoi(N, Src, Aux, Dest, Moves-NMoves) :-
NMoves is 2^N - 1,
length(Moves, NMoves),
move(N, Src, Aux, Dest, Moves-_).
move(1, Src, _, Dest, [Src->Dest|Rest]-Rest) :- !.
move(2, Src, Aux, Dest, [Src->Aux,Src->Dest,Aux->Dest|Rest]-Rest) :- !.
move(N, Src, Aux, Dest, Moves-Rest) :-
N0 is N-1,
move(N0, Src, Dest, Aux, Moves-M1),
move(1, Src, Aux, Dest, M1-M2),
move(N0, Aux, Src, Dest, M2-Rest).
Более читаемый подход может включать использование DCG для скрытиясантехника:
hanoi(N, Src, Aux, Dest, Moves-NMoves) :-
NMoves is 2^N - 1,
length(Moves, NMoves),
phrase(move(N, Src, Aux, Dest), Moves).
move(1, Src, _, Dest) --> !,
[Src->Dest].
move(2, Src, Aux, Dest) --> !,
[Src->Aux,Src->Dest,Aux->Dest].
move(N, Src, Aux, Dest) -->
{ succ(N0, N) },
move(N0, Src, Dest, Aux),
move(1, Src, Aux, Dest),
move(N0, Aux, Src, Dest).