CSA形式のデータ読み込み部 解説 その2
CSA形式の読み込みルーチンについて解説する前に、Bonanzaの設計スタイルについて少し書いておきます。
Bonanzaは、Cで書かれています。C++ではありません。
C++ならば、CSA読み込み部分のプログラムを書くならばCSA用のclassを作って、そのメンバ変数として内部状態(現在の読み込み行を意味するカウンター、読み込み中の行のバッファ、読み込んでいるファイルのファイルポインタetc…)を持たせるのが普通のコーディングスタイルでしょう。
これをCで書くとどうなるかと言うと、Cでは関数は基本的に内部状態を持てませんから(static変数に状態を保存することはできますが、普通そういう書き方はしません)、内部状態に相当するものを外部から(呼び出し側から)与えてやる必要があります。
つまり、関数の引数に、内部状態に相当する構造体のポインタがついてまわることになります。
たとえば次のようなC++のclassがあったとして…。
class FileReader { Result FileOpen(); Result FileClose(); private: FILE* file; // 読み込み中のファイルのファイルポインタ int lineNo; // 読み込み中の行数 };
これをCで書くには次のようになります。
struct fileReader_t { FILE* file; // 読み込み中のファイルのファイルポインタ int lineNo; // 読み込み中の行数 }; Result FileReader_FileOpen(fileReader_t* pF); Result FileReader_FileClose(fileReader_t* pF);
C++,C#,Javaのような言語に慣れ親しんでいるプログラマにとって後者のスタイルはあまり見かけないもので最初は戸惑うかも知れませんが、この前者と後者とが同一であるという視点で捉え直せば、意外とスムーズに理解できると思います。
要するに、この書き方はCでclassを擬似的に表現するための手法です。
ここではこれを擬似classと呼ぶことにします。
そういう視点で見れば、Bonanzaのshogi.hで定義されている、CSA読み込みに使う次の構造体は、CSA読み込み擬似クラスのメンバー変数に相当するものであることが見えてくるかと思います。
typedef struct { union { char str_move[ MAX_ANSWER ][ 8 ]; } info; // CSAファイル上に $ANSWERという表記で局面図に対する解答の指し手が書かれていたときに // それを読み込んで保持しておくためのバッファ。 char str_name1[ SIZE_PLAYERNAME ]; // 先手の名前 char str_name2[ SIZE_PLAYERNAME ]; // 後手の名前 FILE *pf; // 読み込んでいるCSAファイルのファイルポインタ unsigned int games, moves, lines; // ゲームの状態(投了しているかだとか) // 開始局面からの手数 // 読み込み中のCSAファイルの現在解析している行ナンバー } record_t;
なお、上記のソース上のコメントは私が親切でつけておきました。
つづく