読者です 読者をやめる 読者になる 読者になる

人工知能に関する断創録

人工知能、認知科学、心理学、ロボティクス、生物学などに興味を持っています。このブログでは人工知能のさまざまな分野について調査したことをまとめています。最近は、機械学習・Deep Learningに関する記事が多いです。



マップの保存

Pygame

作ったマップを保存できるようにしましょう。マップは1マス8bitのバイナリ形式でファイルに保存します。1マス8bitで表現するので256種類までマップチップが使える計算です。マップの保存はSキーを押してください。ウィンドウが開くのでマップ名を入力します。マップ名を小文字にし、.mapをつけたファイルに格納されます。たとえば、SAVE?ウィンドウでFIELDという名前を入力したらfield.mapに保存されます。

pymap06.zip
f:id:aidiary:20100807180000p:plain

マップの保存

マップの保存はSキー。イベントハンドラを見るとSキーを入力したときマップ名を入力するInputWindowが開き、その名前をMapのsave()に渡しています。

            elif event.type == KEYDOWN and event.key == K_s:
                # マップをセーブ
                name = input_wnd.ask(screen, "SAVE?")
                map.save(name)

次にMapのsave()です。

    def save(self, name):
        """マップをバイナリ形式でfileに保存"""
        file = "%s.map" % (name.lower())
        fp = open(file, "wb")  # バイナリモードで開く
        # 行数、列数はi(int)で保存
        fp.write(struct.pack("i", self.row))
        fp.write(struct.pack("i", self.col))
        # マップチップはB(unsigned char)で保存
        # 8bitなのでマップチップは256種類まで
        fp.write(struct.pack("B", self.default))
        for r in range(self.row):
            for c in range(self.col):
                fp.write(struct.pack("B", self.map[r][c]))
        fp.close()

マップ名(name)をファイル名(file)に変換しています。ファイル名はマップ名を小文字にして.mapをつけたものです。たとえば、SAVE?ウィンドウでFIELDという名前を入力したらfield.mapに保存されます。lower()は文字列を小文字に変換する関数です。

バイナリモードはopen()に"b"を指定します。バイナリの読み書きにはPythonのstructモジュールを使います。データをバイナリ形式に変換するのがstruct.pack()です。第1引数はフォーマット文字でバイナリデータの形式です。第2引数はバイナリに変換したい変数です。上の例では、まず行数と列数を形式"i"で出力しています。iはint型を意味します。intというのはC言語の型であり、一般的には32bit(コンピュータによっては16bit)で-2147483648から2147483647までの数値が表せます。行数と列数を表すには十分です。

次にデフォルトマップチップの番号を"B"で出力しています。Bはunsigned char型を意味します。 unsigned charもC言語の型であり、符号なしの8bitで0から255までの数値が表せます。マップチップは256種類使えると言ったのは0から255まで 256個の数値が使えるからです。次にマップの各マスのマップチップ番号を順に出力しています。これも"B"で出力します。

バイナリ形式

バイナリファイルはテキストファイルと違ってメモ帳などのエディタでは開いても中身が読めません。バイナリファイルを読むにはバイナリエディタというのを使います。バイナリエディタで検索するとたくさん出てくるので好きなのを使ってください。スクリーンショットのfield.mapをバイナリエディタで開くと下のようになります。

f:id:aidiary:20100807180001p:plain

ちょっと読み解いてみます。数字の1つは4bitで2つずつまとめて表示されます。つまり、2つまとめた数字が8bitにあたります。サンプルではまず行数(15)と列数(20)をint型(32bit)で出力しました。32bitということは数字8個分ですね。

 0f 00 00 00 → 15
 14 00 00 00 → 20

バイナリエディタではデータを16進数で表すのが普通です。この場合、16進数0fは2進数で00001111 なので10進数では15です。また16進数14は2進数で00010100なので10進数では20です。ちゃんと格納されていました。次の05はデフォルトマップチップです。16進数05は10進数では5なのでこれは海のマップチップIDですね。キャラクターチップとマップチップ(2008/6/24)参照。他にも03、06、07、08という値が見えますが、これらはそれぞれ草原、森、丘、山のマップチップIDです。バイナリファイルは行・列という概念がなく、数値がだらだら並んだ形式になっているのがよくわかります。

次はこのマップファイルを読み込んでマップを復元する処理を実装します。