[FrontPage ← 先頭のページに戻る]
== デカルト言語のプログラム:サルとバナナ
人工知能風のプログラムをご紹介しましょう。
昔からある有名な問題です。
{{{
天井にバナナが紐で結んで吊るしてあります。
一匹の猿がいます。
猿はバナナを食べたいのですが、背伸びしても跳ねても届きません。
部屋の角には、棒が落ちています。
隣の部屋には大きな箱があります。
猿は、バナナを取れるでしょうか?
}}}
この問題を、デカルト言語で猿を作って解かせてみましょう。
注意) この例題は、最新のdescartes-0.6.0でないと動作しません。
=== 1. 世界の状態の表現
この世界の状態を以下のようなリストで表すこととします。
(状態 猿の位置 猿の高さ 箱の位置 猿の持ち物)
猿の最初の状態は、このように表せます。
(状態 "スタート地点" 地面 "隣の部屋" 手ぶら)
猿は、「スタート地点」の「地面」にいて、箱は「隣の部屋」にあり、
猿は「手ぶら」です。
最終的な目的となる状態は、猿の持ち物にバナナが入っている状態です。
(状態 _ _ _ バナナ)
上記で_となっているのは、無名変数であり、その部分はどのような状態になっていても良いことを表しています。
=== 2. 猿の行動による状態の変化
猿のとれる行動は以下の通りです。
- 棒を使ってバナナを落として、バナナをつかむ
- 部屋の角 で棒を拾う
- 箱に登る
- 箱を押す
- 歩いて移動する
- 棒を投げる
- 箱を持ち上げる
猿の行動は、現在の状態を変化させて、新しい状態に変化させます。
これは次のようなプログラムで表現します。
<action 行動者 行動
前の状態
次の状態 >;
例えば、「#who が、#place1 から #place2 まで歩く」は、こうなります。
<action #who (#who が、#place1 から #place2 まで歩く)
(状態 #place1 地面 #place3 #Hand)
(状態 #place2 地面 #place3 #Hand)>;
他の行動についてもどうなるかちょっと考えてみてください。
(「6. 全体ソース」に解答があります。)
=== 3. 猿の思考ルーチン
猿はオブジェクトとして実装します。
{{{
::<猿
<考える #st> // (1)
<考える #st () #rep>
<printlistnl #rep>
;
<考える (状態 _ _ _ バナナ) #rep #rep>; // (2)
<考える #State1 #rep1 #rep> // (3)
<self #who>
<action #who #Operate #State1 #State2>
<append #rep2 #rep1 (#Operate)>
<考える #State2 #rep2 #rep>
;
>;
}}}
思考ルーチンは、3つの部分でできています。
(1) 1つの引数を持つ <考える> 述語は、最初の状態を #stに設定して
2つの引数を持つ <考える> 述語を呼び出し、
最後にprintlistnlで結果を表示する部分です。
(2) 状態の「猿の持ち物」が、バナナになっています。
つまり、これは最終的な目的の状態を表します。
第2、第3引数の#repには、(3)で後述する猿の行動のログが入っています。
(3) selfは、オブジェクトの名前を獲得します。
actionで、猿の行動を決めます。
appendで、猿の行動#Operateをロギングしていきます。
最後の、<考える> で新しい状態#State2を元に次の行動を模索します。
=== 4. ゴリラとチンパンジー
猿をオブジェクトとして実装したので、これを継承機能を使うと
別のオブジェクトに継承させることができます。
{{{
::<ゴリラ
inherit 猿;
>;
::<"チンパンジー"
inherit ゴリラ;
>;
}}}
ゴリラは猿を継承しています。
チンパンジーは、ゴリラを継承しています。
これで、ゴリラとチンパンジーも猿と同様の思考をして見せます。
=== 5. 実行
さて、お待ちかねの実行結果を表示します。
ゴリラとチンパンジーについては、同じ行動をさせても面白くないので
最初の地点と箱の置き場所を変えてあります。
{{{
$ ./descartes example/saru/sarubanana3-sjis
猿 が、 スタート地点 から 部屋の角 まで歩く
猿 が、部屋の角 で棒を拾う
猿 が、 部屋の角 から 隣の部屋 まで歩く
猿 が、箱を 隣の部屋 から バナナの下 まで押す
猿 が、 バナナの下 で箱に登る
猿 が、棒を使ってバナナを落として、バナナをつかむ
result --
::猿 <考える (状態 スタート地点 地面 隣の部屋 手ぶら)>
-- true
ゴリラ が、 戦場 から 部屋の角 まで歩く
ゴリラ が、部屋の角 で棒を拾う
ゴリラ が、 部屋の角 から 敵地 まで歩く
ゴリラ が、箱を 敵地 から バナナの下 まで押す
ゴリラ が、 バナナの下 で箱に登る
ゴリラ が、棒を使ってバナナを落として、バナナをつかむ
result --
::ゴリラ <考える (状態 戦場 地面 敵地 手ぶら)>
-- true
チンパンジー が、 木星 から 部屋の角 まで歩く
チンパンジー が、部屋の角 で棒を拾う
チンパンジー が、 部屋の角 から 月 まで歩く
チンパンジー が、箱を 月 から バナナの下 まで押す
チンパンジー が、 バナナの下 で箱に登る
チンパンジー が、棒を使ってバナナを落として、バナナをつかむ
result --
::チンパンジー <考える (状態 木星 地面 月 手ぶら)>
-- true
}}}
ゴリラは元特殊部隊員で、チンパンジーは木星帰りで箱に触ったら目覚めてしまったという設定です。
=== 6. 全体ソース
このソースは、ダウンロードにあるリリースされているファイルの中のexample/saruの下にもあります。
---
{{{
<append #X () #X >;
<append (#A : #Z) (#A : #X) #Y>
<append #Z #X #Y >;
<action #who (#who が、棒を使ってバナナを落として、バナナをつかむ)
(状態 バナナの下 箱の上 バナナの下 棒 )
(状態 バナナの下 箱の上 バナナの下 バナナ)>;
<action #who (#who が、部屋の角 で棒を拾う)
(状態 部屋の角 地面 #place2 手ぶら)
(状態 部屋の角 地面 #place2 棒)>;
<action #who (#who が、#place で箱に登る)
(状態 #place 地面 #place #Hand)
(状態 #place 箱の上 #place #Hand)>;
<action #who (#who が、箱を #place1 から #place2 まで押す)
(状態 #place1 地面 #place1 #Hand)
(状態 #place2 地面 #place2 #Hand)>;
<action #who (#who が、#place1 から #place2 まで歩く)
(状態 #place1 地面 #place3 #Hand)
(状態 #place2 地面 #place3 #Hand)>;
<action #who (#who が、棒を投げる)
(状態 #place1 地面 #place2 棒)
(状態 #place1 地面 #place2 手ぶら)>;
<action #who (#who が、箱を持ち上げる)
(状態 #place1 地面 #place1 #Hand)
(状態 #place1 地面 #place1 #Hand)>;
::<猿
<考える #st>
<考える #st () #rep>
<printlistnl #rep>
;
<考える (状態 _ _ _ バナナ) #rep #rep>;
<考える #State1 #rep1 #rep>
<self #who>
<action #who #Operate #State1 #State2>
<append #rep2 #rep1 (#Operate)>
<考える #State2 #rep2 #rep>
;
>;
? ::猿 <考える (状態 "スタート地点" 地面 "隣の部屋" 手ぶら)>;
::<ゴリラ
inherit 猿;
>;
? ::ゴリラ <考える (状態 戦場 地面 敵地 手ぶら)>;
::<"チンパンジー"
inherit ゴリラ;
>;
? ::"チンパンジー" <考える (状態 木星 地面 月 手ぶら)>;
}}}
---