プログラミングを頑張る日記

プログラミングを勉強して、ハッカーになろう

Common Lispを頑張る(10)

ああ〜働きたくないです。
まあそれは置いておいて、久々にLispをやっていきます。

確か前はゲーム用REPLのread部分を実装したのでした。
今日はeval部分だと思います。もう疲れていますが頑張ります。

専用のeval

素のevalを扱うことの危険は、どんなコマンドでもLispコマンドとして
存在していれば実行してしまうことです。
ゲームを提供したら自分のPCを壊されたなんて事態がありえるのは嫌です。
これを避けるのは簡単で、予め決めておいたコマンドだけを受け付ければ良いのですね。
よし!写経します。

CL-USER> (defparameter *allowed-command* '(look walk pickup inventory))
*ALLOWED-COMMAND*
CL-USER> (defun game-eval (sexp)
	   (if (member (car sexp) *allowed-command*)
	       (eval sexp)
	       '(そのコマンドは存在しません。)))
GAME-EVAL
CL-USER> (game-eval (game-read))
wakk 東
(そのコマンドは存在しません。)
CL-USER> (game-eval (game-read))
walk 東
(あなたは活気ある街にいる。 大通りには露店が並んでいて、あちこちで交渉が行われている。 西 には 街道 があり、 はじまりの村 へと続いている。 街の中心
 には 橋 があり、 王様の城 へと続いている。 この場所には 旅人の服 があるかもしれない。 この場所には 栗毛の馬 があるかもしれない。)
CL-USER>

すっごい簡単でした。
まず最初に*allowed-command*にゲーム中実行可能なコマンドのリストを記録しておいて、
game-evalでは入力のコマンド部分をcarで引き出しmemberで*allowed-command*に
存在するか確認して、あれば入力を実行、なければ「そんなの知らない」と伝えてますね。

こんなにさっくり行くならば、game-printもやります。

専用のprint

参考書の中では素のprintの悪いところの最初の点として、
全ての文字が大文字で表示されてしまうことが挙げられています。

......。全部の表示を日本語で実装してしまっています。え〜と、どうしよう。
そうですね…素のprintの困るところ…まずは括弧です。括弧は取っちゃいます。
あとは、句点が出てきたら改行するようにしたいですね。時々変なところで改行されるので。

参考書の例を見ながらやってみます。
......めっちゃ難しいです。まず例のgame-printが難しいです。
とりあえずまずは日本語でも使いたいコマンドが使えるかですね…。

CL-USER> (prin1-to-string '(日本語で使えるのか))
"(日本語で使えるのか)"
CL-USER> (coerce (string-trim "()" (prin1-to-string '(こっちはどうだ))))
; Evaluation aborted on #<SB-INT:SIMPLE-PROGRAM-ERROR "invalid number of arguments: ~S" {10047D19C3}>.
CL-USER> (coerce (string-trim "()" (prin1-to-string '(こっちはどうだ))) 'list)
(#\HIRAGANA_LETTER_KO #\HIRAGANA_LETTER_SMALL_TU #\HIRAGANA_LETTER_TI
 #\HIRAGANA_LETTER_HA #\HIRAGANA_LETTER_DO #\HIRAGANA_LETTER_U
 #\HIRAGANA_LETTER_DA)
CL-USER>

ぐわあああ!全部何というのでしょう、character(?)になってしまいました。
いや…princならなんとかしてくれるかしらん。

CL-USER> (princ (coerce (string-trim "()" (prin1-to-string '(こっちはどうだ))) 'list))
(こ っ ち は ど う だ)
(#\HIRAGANA_LETTER_KO #\HIRAGANA_LETTER_SMALL_TU #\HIRAGANA_LETTER_TI
 #\HIRAGANA_LETTER_HA #\HIRAGANA_LETTER_DO #\HIRAGANA_LETTER_U
 #\HIRAGANA_LETTER_DA)
CL-USER>

むむむ。いや、参考書ではcoerceをもう一発使ってます。こいつがこっちに足りていないようです。
再チャレンジ。

CL-USER> (princ (coerce (coerce (string-trim "()" (prin1-to-string '(こっちはどうだ))) 'list) 'string))
こっちはどうだ
"こっちはどうだ"
CL-USER>

よっしゃあ!これです!え〜とさらにcoerceでリストにしたあと、
句点を見つけたら句点のあとに#\newlineをつけてくれるような関数を経由すれば…。

(defun tweak-text (lst)
	   (let ((item (car lst))
		 (rest (cdr lst)))
	     (cond ((eql item #\IDEOGRAPHIC_FULL_STOP)
		    (cons item #\newline))
		   (t (tweak-text rest)))))

そんなわけで閉店間際のコメダで急いで書いたコードがこちら。
無限ループしてしまいました。
全然止まってくれず最終的にslimeが反応しなくなることで終わりました。
悲しいです。はあ…。やっちった…。
記念すべき第10回でしたがアホを晒してしまいました。

明日はこいつをちゃんとしたものにしたいと思います。
今日はもう寝ます…。おやすみなさい。