このバリアントを使用すると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).