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.