これまで、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プログラムを踏まえて、ウィンドウズプログラムに移植してゆきます。