在河内的prolog塔上实施一个柜台

时间:2011-11-16 02:34:46

标签: prolog counter towers-of-hanoi

我有一个程序在早上使用Prolog。

我正在实施河内塔。

每次打印Move disc number # from _ to _时,我需要帮助的是什么。我需要增加一个计数器,说Move X: "String"字符串是之前要移动的语句。

在程序结束时,我需要打印完成拼图所需的动作总数。我目前以自下而上的方式设置我的程序设置。

3 个答案:

答案 0 :(得分: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('.').

即使上面的代码与您所拥有的代码无关,也应用相同的过程:添加参数以传输Counter并使用递归来递增它。

或者,有global variables但通常不赞成,因为它们易于滥用和编写程序程序。

答案 1 :(得分:1)

而不是写一个do-all谓词,在do-one-thing谓词中打破它:

  1. 编写一个获取光盘数量的谓词并返回解决问题的移动列表(即[1->2, 3->1, ...]
  2. 标准length/2谓词已经允许您计算列表中的移动次数。
  3. 编写一个谓词,以用户友好的格式打印移动列表。
  4. 编写谓词以按顺序调用先前的谓词。

答案 2 :(得分:1)

使用此变体,可以调用hanoi(3,left,middle,right,Moves-NMoves),移动列表将立即传递到Moves,并且所采取的移动数量将实例化为NMoves。可以轻松编写谓词,将每个列表成员格式化为输入/输出。

请注意这里如何使用差异列表以避免昂贵地使用append/3length/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).