6.2 定石クラスの構造と生成 |
本節では定石クラスの構造について説明します。
"opening.c"に定義します。
まずOpeningクラスの構造を以下のように定義します。
struct _Opening { int Num; /* 局面データの数 */ int Max; /* 保持可能な局面データの数 */ PositionData *Data; /* 局面データ */ };
Numは現在登録されている局面データの数です。
Maxは現在確保しているメモリ領域に保持可能な局面データの数です。
Maxを超えて登録する場合には新たにメモリ領域を確保する必要があります。
Dataは局面データの配列です。
1個1個の局面データはPositionDataという型です。
次は局面データについて説明します。
局面データ構造体PositionDataを以下のように定義します。
/* 局面データ */ typedef struct _PositionData PositionData; struct _PositionData { PositionKey key; PositionInfo info; };
局面データはPositionKeyとPositionInfoの2つのデータで構成されます。
PositionInfoは既に出てきましたが局面の評価値等の情報を表します。
PositionKeyは、局面での石の並びと手番を表します。
局面状態を表す構造体PositionKeyの定義は以下の通りです。
/* 盤面の状態をあらわす構造体 bl、bhに手番の石の状態を、wl、whに手番でない石の状態を格納する 石が存在する場合には各ビットを1にする */ typedef struct _PositionKey PositionKey; struct _PositionKey { unsigned long int bl; unsigned long int bh; unsigned long int wl; unsigned long int wh; };
手番の石(黒番なら黒石、白番なら白石)の状態をblとbhに格納します。
各ビットが盤面のマスに対応していて、あるマスに手番の石があればblまたはbhの対応するビットを1にします。
それぞれ32bitなので、両方で64マス分の情報を持つことができます。
(実際には処理系に依存するので、32bitになるようにblとbhの型を決めます)
wlとwhは手番でない石の状態を表します。
定石クラスで使用する定数について説明します。
/* 局面情報のブロックサイズ PositionInfoのメモリ領域はNUM_INFO_BLOCK * sizeof(PositionInfo) の整数倍確保するようにする */ #define NUM_INFO_BLOCK 0x010000
局面情報のブロックサイズとは、局面データ用のメモリ領域を何バイトずつ確保するかを決めるための値です。
局面データの登録を頻繁に行なうと、新たにメモリ領域を確保する必要があります。
最初に多くのメモリ領域を確保するのはメモリの無駄ですし、頻繁にメモリ領域を確保しなおすのもよくありません。
そこで適当なサイズ毎にメモリ領域を確保します。
ここでは、局面データ65536個(16進数で0x010000)毎に新たなメモリ領域を確保するようにします。
定石クラスの構造について説明したので、次はクラスの生成関数について説明します。
static int Opening_Initialize(Opening *self) { memset(self, 0, sizeof(Opening)); self->Num = 0; self->Max = NUM_INFO_BLOCK; self->Data = malloc(self->Max * sizeof(PositionData)); if (!self->Data) { return 0; } return 1; } Opening *Opening_New(void) { Opening *self; self = malloc(sizeof(Opening)); if (self) { if (!Opening_Initialize(self)) { Opening_Delete(self); self = NULL; } } return self; }
Openingクラスに必要なメモリ領域の確保を行なっています。
定石データは1個も登録していないので、メンバNumは0にしておきます。
メンバMaxはNUM_INFO_BLOCKにしておき、定石データ用の領域をその分確保します。
次に定石クラスを破棄する関数Opening_Delete()を記述します。
生成時に確保したメモリ領域を解放します。
static void Opening_Finalize(Opening *self) { if (self->Data) { free(self->Data); } } void Opening_Delete(Opening *self) { Opening_Finalize(self); free(self); }
次節は定石データをファイルから読み込んだり、ファイルに書き込んだりする処理について説明します。