在河内的prolog塔上实现计数器

在河内的prolog塔上实现计数器,prolog,counter,towers-of-hanoi,Prolog,Counter,Towers Of Hanoi,我有一个程序在早上使用Prolog 我正在实施河内塔 我需要的帮助是每次打印将光盘编号从uu移动到。我需要增加一个计数器,说Move X:“String”String是移动内容的前一个语句 在程序结束时,我需要打印完成拼图所需的移动总数。目前,我的程序是自下而上递归设置的。一个常见问题是将IO与计算混为一谈。最好是通过一个包装器谓词和一个随结果实例化的参数来隔离IO 考虑这一点(代码旨在演示计数器的添加,而不是解决问题): 即使上面的代码与您拥有的代码无关,同样的过程也适用:添加参数以传输计数器

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

我正在实施河内塔

我需要的帮助是每次打印
将光盘编号从uu移动到
。我需要增加一个计数器,说
Move X:“String”
String是移动内容的前一个语句


在程序结束时,我需要打印完成拼图所需的移动总数。目前,我的程序是自下而上递归设置的。

一个常见问题是将IO与计算混为一谈。最好是通过一个包装器谓词和一个随结果实例化的参数来隔离IO

考虑这一点(代码旨在演示计数器的添加,而不是解决问题):

即使上面的代码与您拥有的代码无关,同样的过程也适用:添加参数以传输计数器,并使用递归对其进行递增


或者,也有但通常不受欢迎的方法,因为它们很容易被误用和编写过程程序。

与其编写一个do-all谓词,不如将其分解为do-one-thing谓词:

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

  • 使用此变量,可以调用
    hanoi(3,左,中,右,Moves NMoves)
    ,移动列表将实例化为
    移动
    ,移动次数将实例化为
    NMoves
    。可以很容易地编写谓词,将每个列表成员格式化为输入/输出

    注意这里如何使用差异列表来避免昂贵的
    append/3
    hanoi/5
    谓词中的
    length/2
    调用可以证明生成的移动列表大小正确

    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).
    

    最好是显示一些代码。如果没有看到代码的相关部分,很难有任何上下文来回答。对不起,伙计们,我会记得下次发布代码。谢谢你的帮助!format/2对于组合连续的写入/1调用也很有用,例如:format(“使用~w磁盘所需的步骤数为~w.”,[N,Count])。使用DCG来描述列表将使其更具可读性。@mat,这是可能的。我添加了你的建议作为替代方法。
    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).