ピカチュウのセリフをマルコフ連鎖で生成する

ピカチュウのセリフがどういった構造かよく知らないが、想像の範囲でそれらしいものを生成してくれるジェネレータを作ってみた。生成には教科書的な単純なマルコフ連鎖を使っている。現在の状態から、既知の確率で次の状態に遷移する。それだけだと文の切れ目が分からないので、終端かどうかも出力する。

(setq pika-tb ;                  p1p2p3p4k1c1c2c3t1e1e2e3
      (list (list "ピカ"     nil 1 2 2 2 1 9 3 3 1 2 2 4)
            (list "ピッ"     nil 4 1 1 1 1 0 0 0 1 1 1 1)
            (list "ピー"     nil 4 4 0 4 8 0 0 0 3 1 1 1)
            (list "ピッカ"   nil 2 2 2 2 1 4 2 2 1 2 2 2)
            (list "カー"     nil 1 1 1 1 0 3 1 3 1 1 1 1)
            (list "チュウ"   nil 1 1 1 1 0 0 0 0 0 3 2 9)
            (list "チュ〜ウ" nil 0 0 0 0 0 0 0 0 1 3 2 4)
            (list "チュー"   nil 0 1 1 1 0 0 0 0 0 3 0 9)
            (list "、" nil 1 1 1 1)
            (list "。" t   1 1 1 1)
            (list "? " t  1 1 1 1)
            (list "! " t  1 1 1 1 )))

(defun gen-pika-langue ()
  (let ((st 0))
    (lambda ()
      (let ((data (elt pika-tb st)))
        (setq st ; ルーレット選択で次の状態を選択
              (let ((r (random (apply '+ (subseq data 2))))
                    (c 0) (d 0))
                (dolist (arg (subseq data 2) c)
                  (if (< r (incf d arg))
                      (return c) (incf c)))))
        (subseq data 0 2)))))

;生成してみる。
(let ((p (gen-pika-langue)))
  (dotimes (i 10)
    (loop
      (let ((arg (funcall p)))
        (format t "~A" (car arg))
        (if (cadr arg) (return))))))

例では10の文を生成している。結果は次の通り。ピカチュウ! ピカチューピッカピーカーピー、ピッカチュウ! ピッピカチュウ! ピーカーチュー。ピッカチュウピッカ! ピッピー? ピッカー! ピカ! ピッピカ、ピッカ! ピカチュウ