いつも行くガソリンスタンドのバイトの兄ちゃん（工学部３年）と話しをしたら、「今、Pythonの勉強してるんすよ！」って。

「ふーん。俺、Lisｐ････」と言いかけてやめた。

ライブラリが充実していて、一押しだそうな。

随分遠くに来ちゃった感があるな。（遠い目）と、「たそがれ感満載」でスタンドを後にした際、頭の中ではこの音楽が流れていた。

https://www.youtube.com/watch?v=g7l67VKDL8w

今時の若い人は知らないだろうなぁ。いい歌手だったなぁ。（また遠い目）

注）よくカラオケで歌いました。(爆)

いかんいかん。気を取り直して行ってみよう。少数派には少数派の美学があらぁな！

Lispbuilder-sdl を利用したゲームを作成する時のゲームフレームやイメージデータの読み込みの方法は過去にブログに掲載している。

ゲームフレーム ⇒

http://tomekame0126.hatenablog.com/entry/2014/06/26/222706

イメージデータの読み込み ⇒

http://tomekame0126.hatenablog.com/entry/2014/06/28/024155

なので、今回はこのプログラムの特徴的な関数を見てみよう。

( defun Char->element ( char ) ( ecase char ( #\space ' empty ) ( #\# ' wall ) ( #\- ' dirt ) ( #\o ' rock ) ( #\* ' diamond ) ( #\@ ' entry ) ( #\& ' exit )))

このコードは、読み込んだマップデータのキャラクタを実際のイメージデータの名前に合わせるためのもので、lisp では文字を扱う場合 #\ を文字前につける。（当然です）

注）￥はバックスラッシュで表示されるはず

http://www.fireproject.jp/feature/common-lisp/data-structure/string.html

順番は前後するが、次はこれ、マップのロード。

( defun Load-map ( level ) ( let (( filename ( format nil "C:\\work\\Levels\\level~2,'0d.txt" level ))) ( with-open-file ( stream filename ) ( loop for line = ( read-line stream nil nil ) until ( null line ) collect line into lines finally ( return ( Parse-map lines ))))))

マップ（level01.txt level02.txt level03.txt)のどれかを level で指定 （ or 1 2 3) し、マップファイルをＯＰＥＮ。

そして、１行ずつ読み込み（行の最後のnullまで）、１行ずつlinesに集めていく。

イケてるのは loop の使い方。

collect で集めた lines をそのまま return で Parse-map 関数に投げるなんざ、「 Lisp ってのはこう書くのさ！ 」ってコードが語っている。職人だね。

loop ⇒

http://smpl.seesaa.net/article/29800843.html

with-open-file ⇒

http://d.hatena.ne.jp/hiro_nemu/20090425/1240667723

最後は、lines にまとめたデータを Parse-map 関数に returnして、この関数から脱出。(脱獄ではない！）

注）; as -> for とあるのは、もともとは for の部分が as として書かれていたため、いつも使っている for にしただけ

そして、読み込んだ lines の構文解析。

( defun Parse-map ( lines ) ( let* (( width ( length ( first lines ))) ( height ( length lines )) ( data ( make-array ( list height width ))) ( entry nil ) ( exit nil )) ( loop for y below height for line in lines do ( loop for x below width for element = ( Char->element ( aref line x )) do ( setf ( aref data y x ) element ) when ( eql element ' entry ) do ( setf entry ( cons x y )) ( setf ( aref data y x ) ' empty ) when ( eql element ' exit ) do ( setf exit ( cons x y )))) ( make-instance ' level :width width :height height :data data :entry-position entry :exit-position exit )))



lines リストの1行目の length（40） を width とし、リスト全体の length（22） を height に設定。

data は 22 × 40 の配列として設定。

entry(スタート）と exit(ゴール）には nil (初期値) を設定しておく。

ループでは増分の方向を負として、22 から 0 に向かって y を減らしつつ、lines から１ line 読み込む。

読み込んだら、40 から 0 に向かって x を減らしつつ、element に line の x 番目を読み込む。

element を data(22×40）にセットし、element が 'entry のときは nil に設定していた entry にその位置（コンス）をセット。

また 'exit であれば exit にその位置（コンス）をセットする。

最後は、level のインスタンス。

width(横幅 : 40）、height(高さ : 22） data（配列：'empty etc）、entry（入口位置：コンス）、exit（出口位置：コンス）の情報をもつインスタンスを生成。

あっ、diamond-count は今の段階ではコメントアウトしないと SBCL が warning を出すため、うざったいから止めてます。

今日はこんな感じ。