////////////////////////////////
// Class of CBOARD
// for use of MENACE
// Copyright (c) by Ysama, 2021
////////////////////////////////

//定数定義（先手(1)、後手(2)、未打(0)）
#define		FIRST	1
#define		SECOND	2	//-1は、評価で1 x -1 x 1 = -1や-1 x 1 x -1 = 1となるので止めた
#define		VACANT	0

////////////////////////////////////
//BOARD Structure for use of CBOARD
////////////////////////////////////
typedef struct _board {

	char m_Pos[9];
	//	-------		盤面はm_Pos[0]-[8]のchar配列を使う
	//	|0|1|2|		これがMENACEのビーズに相当
	//	-------
	//	|3|4|5|
	//	-------
	//	|6|7|8|
	//	-------
	int m_Outcome;	//試合後DB登録用評価データ（先手勝負(1, -1)、後手勝負(2, -2)）
} BOARD, *PBOARD;

////////////////////////
//CMBOARDクラスヘッダー
//（盤面データのクラス）
////////////////////////
class CBOARD {

protected:										//CBOARDと承継したCMENACEは利用できる
	//変数
	BOARD m_Board;								//試合用盤
	int m_LastMove;								//最終手（0 - 8）
public:
	//関数
	CBOARD();									//コンストラクター（初期化のみ）
	void Init();								//初期化（再ゲーム時に必要）
	BOARD GetBoard() {return m_Board;}			//盤面データ（m_Board）のデータを渡す
	bool MakeMove(int, char);					//手を打つ
	int* CheckBoard();							//盤面を調べる（戻り値は空き位置の配列とその数）
	bool RandomMove(char);						//乱数で手を打つ
	void RecMove(int m) {m_LastMove = m;}		//手を記録する
	int IsOver();								//未了-0、縦横斜めに3つ並んだ-1|2、引き分け-3
	int GetLastMove() {return m_LastMove;}		//最終手を取得する
	int WhoWon() {return m_Board.m_Outcome;}	//勝者（1, 2）敗者（-1, -2）確認用
//	virtual void ShowBoard();					//盤面表示の仮想関数
};

//コンストラクター（初期化のみ）
CBOARD::CBOARD() {

	srand(time(NULL));				//乱数の初期化
	Init();
}

//初期化（再ゲームに必要）
void CBOARD::Init() {

	for(int i = 0; i < 9; i++)
		m_Board.m_Pos[i] = 0;		//m_Board.m_Pos配列を0初期化
	m_Board.m_Outcome = 0;			//m_Outcomeの初期化
	m_LastMove = 0;					//m_LastMoveの初期化
}

//手を打つ
bool CBOARD::MakeMove(int i, char hand) {

	if(m_Board.m_Pos[i] != VACANT)
		return false;
	else {
		m_Board.m_Pos[i] = hand;	//手を打つ
		RecMove(i);					//打手を記録
		return true;
	}
}

//盤面を調べる（戻り値は空き位置の配列とその数）
int* CBOARD::CheckBoard() {

	static int pos[10];
	pos[9] = 0;						//pos[9]に残空き位置数を入れる
	for(int j = 0; j < 9; j++) {
		if(m_Board.m_Pos[j] == VACANT) {
			pos[pos[9]] = j;
			pos[9]++;
		}
	}
	if(!pos[9])
		return NULL;				//打てる場所が無い(pos「9」== 0）
	else
		return pos;					//打てる場所の配列
}

//乱数で手を打つ（打てない場合、不可フラグをたて、falseを返す）
bool CBOARD::RandomMove(char hand) {

	int* cp  = CheckBoard();
	if(!cp[9])						//cp[0] - cp[8]迄が空き位置の添字、cp[9]が残空き位置数
		return false;
	else {
		int i = cp[rand() % cp[9]];
		MakeMove(i, hand);
		RecMove(i);					//打手を記録
		return true;
	}
}

int CBOARD::IsOver() {

	int res;			//勝負の進行状態を表す戻り値
	if(!CheckBoard())	//残空き位置無し（全て埋まって勝敗が決した時は書き直される）
		res = 3;		//引き分け状態が初期値
	else
		res = 0;		//空き位置があれば未了状態が初期値
	int chk;			//縦横斜め3つの手の積（先手なら1、後手なら8になる）
	if((chk = m_Board.m_Pos[0] * m_Board.m_Pos[1] * m_Board.m_Pos[2]) == 1)	//横第1行
		res = FIRST;	//先手勝利
	if(chk == 8)
		res = SECOND;	//後手勝利
	if((chk = m_Board.m_Pos[3] * m_Board.m_Pos[4] * m_Board.m_Pos[5]) == 1)	//横第2行
		res = FIRST;	//先手勝利
	if(chk == 8)
		res = SECOND;	//後手勝利
	if((chk = m_Board.m_Pos[6] * m_Board.m_Pos[7] * m_Board.m_Pos[8]) == 1)	//横第3行
		res = FIRST;	//先手勝利
	if(chk == 8)
		res = SECOND;	//後手勝利
	if((chk = m_Board.m_Pos[0] * m_Board.m_Pos[3] * m_Board.m_Pos[6]) == 1)	//縦第1列
		res = FIRST;	//先手勝利
	if(chk == 8)
		res = SECOND;	//後手勝利
	if((chk = m_Board.m_Pos[1] * m_Board.m_Pos[4] * m_Board.m_Pos[7]) == 1)	//縦第2列
		res = FIRST;	//先手勝利
	if(chk == 8)
		res = SECOND;	//後手勝利
	if((chk = m_Board.m_Pos[2] * m_Board.m_Pos[5] * m_Board.m_Pos[8]) == 1)	//縦第3列
		res = FIRST;	//先手勝利
	if(chk == 8)
		res = SECOND;	//後手勝利
	if((chk = m_Board.m_Pos[0] * m_Board.m_Pos[4] * m_Board.m_Pos[8]) == 1)	//斜め第1列
		res = FIRST;	//先手勝利
	if(chk == 8)
		res = SECOND;	//後手勝利
	if((chk = m_Board.m_Pos[2] * m_Board.m_Pos[4] * m_Board.m_Pos[6]) == 1)	//斜め第2列
		res = FIRST;	//先手勝利
	if(chk == 8)
		res = SECOND;	//後手勝利
	//未了、引き分けでなければ勝者を記録する（DB登録用）
	if(res == FIRST || res == SECOND)
		m_Board.m_Outcome = res;	//勝者は正の整数
	return res;
}
/*
//盤面表示関数（CUI版−仮想関数で承継時オーバーライド可能）
void CBOARD::ShowBoard() {

	char c;
	cout << "-------" << endl;
	for(int i = 0; i < 9; i++) {
		switch(m_Board.m_Pos[i]) {
		case FIRST:
			c = 'O';
			break;
		case SECOND:
			c = 'X';
			break;
		case VACANT:
			c = ' ';
			break;
		}
		cout << "|" << c;
		if((i % 3) == 2)
			cout << "|" << endl << "-------" << endl;
	}
}
*/
