我有一个程序在早上使用Prolog。
我正在实施河内塔。
每次打印Move disc number # from _ to _
时,我需要帮助的是什么。我需要增加一个计数器,说Move X: "String"
字符串是之前要移动的语句。
在程序结束时,我需要打印完成拼图所需的动作总数。我目前以自下而上的方式设置我的程序设置。
答案 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->2, 3->1, ...]
)length/2
谓词已经允许您计算列表中的移动次数。答案 2 :(得分: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).