これまで、BOARD構造体、それを使うCBOARDクラスおよびそれに所謂「マッチ箱計算機」機能を付加したCMENACEクラスを作りましたので、それをテストしてみましょう。まずはCUI テストプログラムを書きます。

 

///////////////////////////////
// Console program for CMENACE
///////////////////////////////
#include    <conio.h>    //getch()使用の為
#include    <stdlib>    //srand()、rand()使用の為
#include    <iostream>    //cout、cin使用の為
#include    <windows.h>    //Win32使用の為

//(解説:インクルードファイルの理由はコメント通りです。最後にBOARDデータの読み書きでWinAPIを使いました。)

using namespace std;
//(解説:これを忘れないでくださいね。)

#include    "CMENACE.h"
//(解説:前回までに作ったCMENACEクラスの宣言と定義ファイルです。)

int PlayerInput(int&, char*);    //人間の打ち手入力関数(CUIのみ)
//(解説:末尾にコンソール入力用の関数があります。)

//メイン関数
int main(int argc, char **argv) {

//(解説:懐かしいCの標準的なmain関数の記述です。)
 

    CMENACE menace;    //(解説:CMENACEのインスタンスです。)
    //BOARD構造体のサイズ確認
    cout << "BOARD構造体のサイズ = " << sizeof(BOARD)  << "バイト" << endl;
    //CBOARD変数のサイズ確認
    cout << "CBOARDのサイズ = " << sizeof(CBOARD)  << "バイト" << endl;
    //CMENACE変数のサイズ確認
    cout << "CMENACEのサイズ = " << sizeof(CMENACE)  << "バイト" << endl << endl;

//(解説:テストなので、こんな確認を行っています。それぞれ16、20、52になるはずです。)

    //データベースにデータを読み込む
    menace.BoardRead("MENACE.dat");

//(解説:CMENACEのメンバー関数によりDB登録データを読みます。最初はないのでエラーになりますが、放っておいてください。)

    //先手、後手、機械対戦の選択確認(結果はyou変数)
    cout << "先手(1)、後手(2)または機械対戦(3)を選択してください" <<endl;
    int you = 0;
    while(you < 1 || you > 3) {
        cin >> you;
    }

//(解説:先手、後手の選択です。PCによる自動対戦は3になります。)    

//盤面の座標表示
    cout << "<<盤面座標>>\r\n-------\r\n|0|1|2|\r\n-------\r\n|3|4|5|\r\n-------\r\n|6|7|8|\r\n-------\r\n>>>>>><<<<<<" << endl;

//(解説:人の手をどのように打つかわかるように、盤面と番号を表示します。)

    //対戦200回なので機械対戦がお勧め

//(解説:200回付き合うと疲れます。途中からでも'9'を入力すると機械対戦に移行します。)
    for(int i = 0; i < 200; i++) {
        menace.Init();

//(解説:CMENACEの初期化です。毎対戦でこれを行うことが必要です。)
        //変数宣言
        int res = 0;    //未了0、先手勝利1、後手勝利2、引き分け3

//(解説:結果データです。当時はコメント通りでしたが、現在は未了0、先手勝利1、後手勝利2、引き分け3、先手敗北-1、後手敗北-2になっています。)
        int times = 0;
//(解説:手の数です。)

        //対戦開始
        do {
            switch(you) {

(解説:以下人間が先手、人間が後手、機械対戦の区分で先手番(手の数が偶数)、後手番(手の数が奇数)で処理をします。)
            case 1:    //先手
                if(!(times % 2))    //先手打
                    //CUI入力
                    menace.MakeMove(PlayerInput(you, menace.GetBoard().m_Pos), you);
                else {            //後手打
                    if(!menace.AutoMove(2)) {        //打つ手がない場合
                        res = menace.WhoWon();        //後手が敗北 
(解説:所謂「投了」です。)
                    }
                }
                menace.ShowBoard();
                break;
            case 2:    //後手
                if(!(times % 2)) {    //先手打
                    if(!menace.AutoMove(1)) {        //打つ手がない場合
                        res = menace.WhoWon();        //先手が敗北 
(解説:所謂「投了」です。)
                    }
                }
                else            //後手打
                    menace.MakeMove(PlayerInput(you, menace.GetBoard().m_Pos), you);
                menace.ShowBoard();
                break;
            case 3:    //機械対戦
                if(!(times % 2)) {    //先手打
                    if(!menace.AutoMove(1)) {        //打つ手がない場合
                        res = menace.WhoWon();        //先手が敗北 
(解説:所謂「投了」です。)
                    }
                }
                else {            //後手打
                    if(!menace.AutoMove(2)) {        //打つ手がない場合
                        res = menace.WhoWon();        //後手が敗北 
(解説:所謂「投了」です。)
                    }
                }
                break;
            }
            times++;
            if(!res && times > 4)

(解説:。第4手(timesは3)までは勝敗が付かないので。また条件に!res (res == 0) としているのは、投了の場合、resが-1か-2になっているのでその値を保存する為です。)

                res = menace.IsOver();

(解説:対戦中(res == 0)の場合、勝敗確認を行います。)
        } while(!res);

(解説:勝敗結果resは↑の通り、先手勝利1、後手勝利2、引き分け3、先手敗北-1、後手敗北-2になっています。)
        cout << ">>>第" << i + 1 << "回対戦-";
        switch(res) {
        case 1:
            cout << "先手の勝ち-終了時盤面<<<" << endl;
            menace.Register();        //終了盤面の記録
            menace.ShowBoard();
            cout << "(menace.WhoWon() = " << menace.WhoWon() << ")" << endl << endl;
            cout << "後手の負け-終了一手前盤面<<<" << endl;
            menace.PushBack();        //終了一手前盤面
            menace.Register();        //終了一手前盤面の記録
            break;
        case 2:
            cout << "後手の勝ち-終了時盤面<<<" << endl;
            menace.Register();        //終了盤面の記録
            menace.ShowBoard();
            cout << "(menace.WhoWon() = " << menace.WhoWon() << ")" << endl << endl;
            cout << "先手の負け-終了一手前盤面<<<" << endl;
            menace.PushBack();        //終了一手前盤面
            menace.Register();        //終了一手前盤面の記録
            break;

(解説:勝敗結果resが先手勝利1、後手勝利2と正の場合、打ち手の勝利盤面のみならず、一手前の相手の敗北盤面も登録します。)

        case 3:
            cout << "引き分け-終了時盤面<<<" << endl;
            break;

(解説:引き分けは戦略的価値がなく、DB登録しません。)
        case -1:
            cout << "先手の負け-終了時盤面<<<" << endl;
            menace.Register();        //終了盤面の記録
            break;
        case -2:
            cout << "後手の負け-終了時盤面<<<" << endl;
            menace.Register();        //終了盤面の記録
            break;

(解説:勝敗結果が先手敗北-1、後手敗北-2と負の場合、打ち手の敗北盤面を登録します。なお、ウィンドウズ版は勝敗数を記録するので、先手の負け==後手の勝ち<同逆>で記録しています。)

        }
        menace.ShowBoard();
        cout << "(menace.WhoWon() = " << menace.WhoWon() << ")" << endl << endl;

(解説:対戦終了時の盤面と、正の結果では一手前の盤面を表示し、m_Outcomeの値をWhoWon()で表示します。)
    }

(解説:以下は200対戦終了後の処理です。)
    cout << "データベースのデータ数は" << menace.DBSize() << "です。" << endl;    
    menace.BoardWrite("MENACE.dat");

(解説:毎回終了時にdataを保存します。

    //Pause
    getch();

(解説:ウィンドウを閉じないようにする定番ですね。)
    return 0;
}

(解説:以上でテストプログラムは終わりです。以下はコンソールから人間の入力を受ける関数です。)
//CUIのみ
int PlayerInput(int& you, char* pos) {

    switch(you) {
    case 1:
        cout << "先手";
        break;
    case 2:
        cout << "後手";
        break;
    default:
        return -1;
    }
    cout << "は打つ場所(0 - 8)を選んでください('9'は機械対戦へ移行)" << endl;
    int move = -1;
    while(move < 0 || move > 8) {
        cin >> move;
        if(move == 9) {
            you = 3;
            for(int i = 0; i < 9; i++) {
                if(!pos[i])
                    move = i;
            }
            return move;
        }
        if(pos[move]) {
            cout << "そこは既に打たれています" << endl;
            move = -1;
        }
    }
    return move;
}

 

それではこのテストプログラムをBCC102でコンパイルしてみてください。BCC55ではコンパイルできないのでバッチファイル例を示します。

【テストプログラムコンパイル用バッチファイル例】

"C:\Borland\BCC102\bin\bcc32c.exe" "C:\Users\(パス)\MENACE\MENACE.cpp" -tC -w
del "C:\Users\(パス)\MENACE\MENACE.tds"
pause

 

次回からは上記CUIプログラムを踏まえて、ウィンドウズプログラムに移植してゆきます。