3

私はPrologを使って午前中に予定されているプログラムを持っています。

私はハノイの塔を実装しています。

私が助けを必要としているのは、それが印刷されるたびMove disc number # from _ to _です。Move X: "String"文字列が何を移動するかについての前のステートメントであるというカウンターをインクリメントする必要があります。

プログラムの最後に、パズルを完成させるために取った動きの総数を印刷する必要があります。現在、プログラムを再帰的にボトムアップでセットアップしています。

4

3 に答える 3

1

一般的な問題の1つは、IOを計算と混合しておくことです。結果でインスタンス化される引数を持つラッパー述語を使用して、IOを分離することをお勧めします。

これを考慮してください(コードは、問題を解決するのではなく、カウンターの追加を示すことを目的としています):

% one move
move(1,X,Y,_,_,1) :-                           
    write('Move top disk from '), 
    write(X), write(' to '), write(Y), nl.

move(N,X,Y,Z,Count,Counter) :- 
    N>1, 
    M is N-1,
    Countplus is Count*2,        % binary recursion tree
    move(M,X,Z,Y,Countplus,C1), 
    move(1,X,Y,_,Countplus,C2),
    move(M,Z,Y,X,Countplus,C3),
    Counter is C1+C2+C3.         % sum of moves

towers(N,X,Y,Z) :-
    Count is N*N-1,
    move(N,X,Y,Z,Count,Counter),                       
    % you can now do whatever you want with Counter, e.g. print it:
    write('The number of steps required with '),
    write(N), write(' disks is '), write(Count), write('.').

上記のコードが現在のコードに関連していない場合でも、同じ手順が適用されます。引数を追加してカウンターを転送し、再帰を使用してそれをインクリメントします。

あるいは、グローバル変数がありますが、手続き型プログラムの誤用や記述が容易であるため、通常は眉をひそめます。

于 2011-11-16T08:21:15.050 に答える
1

do-all述語を作成する代わりに、do-one-thing述語に分割します。

  1. ディスクの数を取得し、問題を解決する動きのリストを返す述語を記述します(つまり[1->2, 3->1, ...]
  2. 標準のlength/2述語では、リスト上の移動の数をすでにカウントできます。
  3. 移動のリストをユーザーフレンドリーな形式で印刷する述語を記述します。
  4. 前の述語を順番に呼び出す述語を記述します。
于 2011-11-16T08:49:06.637 に答える
1

このバリアントを使用すると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).
于 2016-03-14T01:29:39.757 に答える