You selected pail1.pl
% pail pazzle 27-29 Oct 2001
% 水差し問題 pail('4Lj','3Lj').
% modified: 23 Dec 2002.
% modified: 2008.1.17 unicode(utf-8)
% test command go1, go2, and plan have added.
go1:-test(state(2,0),1).
go2:-test(state(2,0),2).
plan(A,B,L):-pail(state(2,0),A,B,L).
%%%%%%% ルールベース %%%%%%%%
% 水槽から桶に汲む。水槽から桶に吐き出す。
rule(1,state(X,0)->state(X,3)).
rule(2,state(0,Y)->state(4,Y)).
rule(3,state(X,Z)->state(X,0)):- Z > 0, Z =< 3, X > 0.
rule(4,state(Z,Y)->state(0,Y)):- Z > 0, Z =< 4, Y > 0.
% 桶の水が空になるまで、他方の桶へ注ぎ込む。
rule(5,state(Z,Y)->state(X,0)):- Z < 4, Y > 0, (X is Y + Z, X < 4; X is 4).
rule(6,state(X,Z)->state(0,Y)):- Z < 3, X > 0, (Y is X + Z, Y < 3; Y is 3).
% 他方が一杯になるまで、他方へ注ぐ。
rule(7,state(Z,Y)->state(X,3)):- Z > 0, Z >= 3 - Y, X is Z - (3 - Y).
rule(8,state(X,Z)->state(4,Y)):- Z > 0, Z >= 4 - X, Y is Z - (4 - X).
% ルールの説明文(日本語)
explaining_rule(1,'水槽から3リットルの桶一杯に水を汲む。').
explaining_rule(2,'水槽から4リットルの桶一杯に水を汲む。').
explaining_rule(3,'水槽へ3リットルの桶の水をすべて捨てる。').
explaining_rule(4,'水槽へ4リットルの桶の水をすべて捨てる。').
explaining_rule(5,'3L桶の水を、空になるまで、4L桶に注ぎ込む。').
explaining_rule(6,'4L桶の水を、空になるまで、3L桶に注ぎ込む。').
explaining_rule(7,'3L桶がちょうど一杯になるまで、4L桶の水を注ぐ。').
explaining_rule(8,'4L桶がちょうど一杯になるまで、3L桶の水を注ぐ。').
%%%%%%% 推論エンジン %%%%%%%%
% プランニング(計画立案)。
pail(state(0,0),[],[],0).
pail(state(4,3),[],[],0).
pail(Goal,[G1|H],[N|Hn],L):-
% リストから項(Term)を作る。
G1 =.. [state,X1,Y1], % G1 = state(X1,Y1) でも可。
Goal =.. [state,X,Y], % Goal = state(X,Y) でも可。
/*
あるいはルールの頭で次のように直接指定すると、後戻りを省略できる。
pail(state(X,Y),[state(X1,Y1)|H],L):-
一方、変数GoalやG1を使うと、本体の後ろの部分で短く書ける。
*/
length([G1|H],L),
% リストの長さをコントロールする。
% (L > 6 -> !,write('end'));
L1 is L - 1,
% リカージョン(再帰)
pail(G1,H,Hn,L1),
rule(N,G1->Goal),
Goal \= G1,
% 以下は数が非束縛(unbound)になるのを防止する。
Z4 = [0,1,2,3,4],
Z3 = [0,1,2,3],
member(X,Z4),
member(Y,Z3),
member(X1,Z4),
member(Y1,Z3),
% 巡回(循環)を避ける。
\+ member(Goal,H),
write(N).
%%%%%%% 対話インタフェース %%%%%%%%
% といっても対話的でないユーザーインタフェース用ルーチンにすぎません。
test(Goal,2):-
Goal=.. [state,_X,_Y],
pail(Goal,H,Hn,_L),!,
nl,nl,write('手順に沿って桶の水量を絵にする:'),nl,
reverse(H,H1),reverse(Hn,Hn1),
graphic_plan(H1,Hn1),
graphic_plan([Goal],[stop]),
write(' end'),nl.
test(Goal,Eflag):-
Goal=.. [state,_X,_Y],
pail(Goal,H,Hn,L),!,
nl,nl,write('目盛りのない4リットルと2リットルの2つの桝で'),
nl,write('2リットル汲むための手順:'),nl,
reverse(H,H1),reverse(Hn,Hn1),
nl,(Eflag = 1 -> explain_plan(H1,Hn1); true),
write(' end'),nl,%write(H1),
nl,write(' 以上のように '),write(Goal),write(' に達するまで '),
write('合計 '),write(L),write(' 回汲みます。'),nl.
% 求めた行動プランの中のルール適用手順を説明する。
explain_plan([],[]).
explain_plan([S1|RemainPlan],[N|RemainRules]):-
%rule(N,S2->S1),
explaining_rule(N,E),
tab(1),write(S1),write(' >'),write('rule '),
write(N),write(': '),write(E),
write('>'),nl,
explain_plan(RemainPlan,RemainRules).
graphic_plan([],[]).
graphic_plan([S1|RemainPlan],[N|RemainRules]):-
%rule(N,S2->S1),
S1 = state(X,Y),
graph_pail(4,X),
graph_pail(3,Y),
tab(1),write(S1),write(' >'),write('rule '),
write(N),write('>'),nl,
graphic_plan(RemainPlan,RemainRules).
% 絵を出す。
graph_pail(4,0):-
tab(5),write('4L:'),write('|----|'),tab(5).
graph_pail(4,1):-
tab(5),write('4L:'),write('|#---|'),tab(5).
graph_pail(4,2):-
tab(5),write('4L:'),write('|##--|'),tab(5).
graph_pail(4,3):-
tab(5),write('4L:'),write('|###-|'),tab(5).
graph_pail(4,4):-
tab(5),write('4L:'),write('|####|'),tab(5).
graph_pail(3,0):-
tab(5),write('3L:'),write('|---|'),tab(5).
graph_pail(3,1):-
tab(5),write('3L:'),write('|#--|'),tab(5).
graph_pail(3,2):-
tab(5),write('3L:'),write('|##-|'),tab(5).
graph_pail(3,3):-
tab(5),write('3L:'),write('|###|'),tab(5).
%%%%%% おまけ(屑籠) %%%%%
% 以下は最初に考えたプログラム:スタック溢れする。
% 他方が空になるまで、他方から注ぎ込む。
pail1(4,Z):-
pail(3,X), pail(4,Y), Z is X + Y,
X >= 0, Y >= 0, Z > 0, Z < 4,
X =< 3, Y =< 4, Z < 4, Z > Y,
write_pail(4,Z).
pail1(3,Z):-
pail(4,X), pail(3,Y), Z is X + Y,
X >= 0, Y >= 0, Z > 0, Z < 3,
X =< 4, Y =< 3, Z < 3, Z > Y,
write_pail(3,Z).
% 他方が一杯になるまで、他方へ注ぐ。
pail1(4,Z):-
pail(3,X), pail(4,Y), Z is Y - (3 - X), %or W is 3 - X, W is Y - Z,
X >= 0, Y >= 0, Z > 0,
X =< 3, Y =< 4, Z < 4, Z < Y,
write_pail(4,Z).
pail1(3,Z):-
pail(4,X), pail(3,Y), Z is Y - (4 - X), %or W is 4 - X, W is Y - Z,
X >= 0, Y >= 0, Z > 0,
X =< 4, Y =< 3, Z < 3, Z < Y,
write_pail(3,Z).
return to front page.