我保留原回答,因为它提供了一些值得思考的部分(而且问题只涉及实现空操作)。这里提供完整的实现:
:- use_module(library(clpfd)).
bucket_capacity(b1,7).
bucket_capacity(b2,3).
bucket_capacity(b3,5).
state_bucket_value(buckets(X, _, _),b1,X).
state_bucket_value(buckets(_, Y, _),b2,Y).
state_bucket_value(buckets(_, _, Z),b3,Z).
state_updated_bucket_value(buckets(_, Y, Z), buckets(X0, Y, Z ), b1, X0).
state_updated_bucket_value(buckets(X, _, Z), buckets(X, Y0, Z ), b2, Y0).
state_updated_bucket_value(buckets(X, Y, _), buckets(X, Y, Z0), b3, Z0).
state_goesto_action(S0, S0, []) :-
S0 = buckets(X,Y,Z),
bucket_capacity(b1,X),
bucket_capacity(b2,Y),
bucket_capacity(b3,Z).
state_goesto_action(S1, S2, [empty(Bucket) | History]) :-
state_updated_bucket_value(S1, S2, Bucket, 0),
state_goesto_action(_S0, S1, History).
state_goesto_action(S1, S3, [pour(From,To) | History]) :-
bucket_capacity(b1,Max),
state_bucket_value(S1,From,X),
state_bucket_value(S1,To,Y),
From0 #= min(X+Y, Max),
To0 #= max(X-Y, 0),
state_updated_bucket_value(S1, S2, From, From0),
state_updated_bucket_value(S2, S3, To, To0),
state_goesto_action(_S0, S1, History).
要找出一个恰好有一升水的桶,我们可以列举所有可能的情况:
?- length(L,_), state_bucket_value(S,_,1), state_goesto_action(_, S, L).
L = [pour(b1, b3), pour(b1, b2), empty(b1), pour(b1, b3)],
S = buckets(5, 0, 1) ;
L = [pour(b1, b3), pour(b1, b2), pour(b1, b1), pour(b1, b3)],
S = buckets(5, 0, 1) ;
L = [pour(b1, b3), pour(b1, b2), pour(b2, b1), empty(b1)],
S = buckets(7, 0, 1) ;
L = [pour(b1, b3), pour(b1, b2), pour(b2, b1), pour(b1, b1)],
[...].
为了检查谓词是否可逆:
?- L = [pour(b1, b3), pour(b1, b2), empty(b1), pour(b1, b3)], state_goesto_action(_, S, L).
L = [pour(b1, b3), pour(b1, b2), empty(b1), pour(b1, b3)],
S = buckets(5, 0, 1) ;
false.
编辑:为了加快计算速度,删除了域限制(我们从一个固定的状态开始,所以限制条件总是具有确定的值,并且可以在不进行标记的情况下传播)。