Prog-G

岐阜大学プログラミングサークル

新元号も発表されたしLisp入門する

Lisp 言語

タイトルの通りです。 一度 Lisp をやっておきたいと思っていたところで、ネタを思いついたのでコーディングします。

環境

処理系は SBCL を使います。 Common Lisp の強力な処理系のひとつです。 機械語にコンパイルされるのでとても速いです。

前に少し流行ったネタですが、元号でこれをやろうと思います。

汎用ズンドコキヨシ関数をつくる

random-choose はリストから要素を無作為に 1 つ選び取る関数、take はリスト先頭からある数を上限に要素を抜き出したリストを返す関数です。 zundoko が汎用ズンドコキヨシ関数です。

(defun random-choose (ls)
  (nth (random (length ls)) ls))

(defun take (ls n)
  (if (or (<= n 0) (null ls))
    nil
    (cons (first ls) (take (rest ls) (1- n)))))

(defun zundoko (words target outs final)
  (let ((word (random-choose words))
        (order (reverse target)))
    (format t word)
    (let ((ws (take (cons word outs) (length target))))
      (if (equal order ws)
        (progn (princ #\newline)
        (format t final))
        (zundoko words target ws final)))))

ズンドコキヨシ関数は再帰的になっていて、4 つの引数と共に使用します。

(defun zundoko-kiyoshi ()
  (zundoko '("ズン" "ドコ") '("ズン" "ズン" "ズン" "ズン" "ドコ") () "キ・ヨ・シ!"))

words に出力候補の文字列のリストを入れます。
target に正解の出力順で文字列のリストを入れます。
outs は前の出力を保持するための引数です。 最初は空リストを渡します。
final は最後に出力する文字列を入れます。

注意点として出力候補の文字列は他の文字列を作れないような集合である必要があります。 '("ズン" "ドコ" "ズ" "ン") のようなものを入れると期待していないような結果が出力されます。

昭和平成をランダムに出力して揃ったら令和を出力する

前節の例に倣えば簡単です。 地味すぎるのでテキストを多少装飾しています。

(defun zundoko-reiwa ()
  (zundoko '("昭" "和" "平" "成") '("昭" "和" "平" "成") ()
   "∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞~%        ■■■□ 令  和 □■■■~%∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞"))

これで遊べば新元号にもすぐ慣れるでしょう。

実行ファイルを作ってみる

SBCL は単体実行可能なネイティブバイナリを吐くことができます。 REPL で必要なファイルをロードしたあとに sb-ext:save-lisp-and-die を実行しましょう。

(load "zundoko.lisp")
(load "zundoko-reiwa.lisp")
(sb-ext:save-lisp-and-die "zundoko-reiwa.exe" :toplevel #'zundoko-reiwa :executable t :application-type :console)

これで配布もバッチリです(ランタイムを含むのでファイルサイズが大きいという欠点はありますが)。 友達に送りつけると良いでしょう。

参考

xyzzy Lisp Programming 入門に非常に良さそうなサイトです。

Land of Lisp 愉快な書籍です。