画像は Land of Lisp 10 章で作るシミュレーションの世界にて100万日が経過した状態。
遺伝子とエネルギーを持った動く動物が、草と森がある世界で動きまわって食事をし、無性生殖で繁殖する世界のシミュレーション。動物は遺伝情報に従い特定の動きを見せ、動くことでエネルギーを消費する。草を食べることでエネルギーを補充、繁殖でエネルギーを大幅に消費、エネルギーが足りないと繁殖できない、エネルギーが切れると死ぬ、というもの。
ライフゲームも似たようなもんだよね。
プログラムの大部分は本に載っているCommon Lispのコードと翻訳者であるshiroさんが公開されているGaucheによるコードを基に、少し改造していくつかの条件をパラメータで渡せるコマンドにしてみたもの。
パラメータをいじって30万日くらい動かすと結果が違って楽しい。動作はコマンドを実行してEnterを押すごとに世界が1日進む。300000などの数値を打ち込んでEnterを押すとその分日数が経過する。
さて、読んでいてよくわからなかったのが、P.202の turn 手続きで移動方向を決める部分。説明を読んでもいまいち意味がわからなかった。angle 手続きを呼び出す辺り。angle の定義はこれ。
(define (angle genes x) (let1 xnu (- x (car genes)) (if (< xnu 0) 0 (+ 1 (angle (cdr genes) xnu)))))
自分なりに書きなおしてみたのはこれ。
(define (angle genes x) (let rec ((genes genes)(x x)(acc 0)) (let1 xnu (- x (car genes)) (if (< xnu 0) acc (rec (cdr genes) xnu (+ acc 1))))))
angle 手続き事態は難しくないけど、これを使って何をやってるのかがわからなかった。
angle の仕事は、引数 x を基に、引数 genes(リスト)から一つ要素を選び、選ばれた要素のインデックスを返すこと。例えば、genes が (1 1 10 5 2 1 1 1) だった場合、合計が22なので x は0〜21のランダムな数値(angle を呼び出す側で決められる)で束縛される。angle の評価結果として出現する頻度が最も高いのが2、次が3、その次が4。
絵に書くとこんな感じか。絵の上の行の数値が x 、下が選択される要素。
今この絵を描いていて思いついたけど、以下のようなリストからランダムに選ぶのと同じってことだな。
(use srfi-27) (let1 genes '(1 1 10 5 2 1 1 1) (apply append (map (^(g i) (iota g i 0)) genes (iota (length genes))))) ;; => (0 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 4 4 5 6 7)
ということで、angle 手続きは下記のようなものでも良いということか。
(define (angle genes x) (~ (apply append (map (^(g i) (iota g i 0)) genes (iota (length genes)))) x))
余談
これ、条件をちゃんと考えたら「ライフメーカーの掟」のプロローグ部分(ロボットがバグって進化し始める)のシミュレーション作れるんじゃないの。 (「ロボットがバグって進化し始める」っていう説明ではすごくちゃちなものに聞こえてしまうな。これをホーガン氏が書くとどえらい壮大なことになるんだよなあ。) このシミュレーションプログラムを有性生殖にして工場を作るだけでも近いものになりそうだな、という話。
0 件のコメント:
コメントを投稿