#include "stdafx.h"
#include "Board.h"

#define countof(x) sizeof(x) / sizeof(x[0])

void Board::GenerateMoves()
{
	int cnt = 0;
	MoveSet& turnMoveSet = GetTurnMoveSet();
	for (int y = COL_MEM_SIZE; y < CELLS_COUNT - COL_MEM_SIZE; y += COL_MEM_SIZE) {
		for (int x = 1; x <= COL_SIZE; x++) {
			int pos = x + y;
			Move& move = turnMoveSet.data[cnt];
			move.drop_pos = pos;
			CompletionRevInfo(move);
			if (!move.isInvalid()) {
				cnt++;
			}
		}
	}
	turnMoveSet.count = cnt;
}

void Board::Do(Move *move)
{
	moves_log.push_back(*move);
	cells[move->drop_pos] = color_of_turn;
	for (int i = 0; i < move->rev_pos_count; i++) {
		cells[move->rev_pos[i]] = color_of_turn;
	}
	color_of_turn = -color_of_turn;
	//次の手を生成する。
	turn_count++;
	GenerateMoves();
	//打つところがなければパスする。
	if (GetTurnMoveSet().isEmpty()) {
		color_of_turn = -color_of_turn;
		//自分も相手も打つことができなければゲーム終了
		GenerateMoves();
		if (GetTurnMoveSet().isEmpty()) {
			//ゲーム終了
		}
	}
}

void Board::Undo()
{
	//最後の着手に注目する。
	Move &undoinfo = moves_log.back();
	//ひっくり返した石を元の色に戻す。
	for (int i = 0; i < undoinfo.rev_pos_count; i++) {
		cells[undoinfo.rev_pos[i]] = -undoinfo.color;
	}
	//置いた場所から石を取り除く
	cells[undoinfo.drop_pos] = EMPTY;
	//手番を元に戻す。
	color_of_turn = undoinfo.color;
	//棋譜から最後の着手を除く。
	moves_log.pop_back();
	//手数を減らす。
	turn_count--;
}



void Board::CompletionRevInfo(Move & move)
{
	const int UP = -COL_MEM_SIZE;
	const int DOWN = COL_MEM_SIZE;
	const int LEFT = -1;
	const int RIGHT = 1;

	int directions[8] = {
		UP,
		DOWN,
		LEFT,
		RIGHT,
		UP + RIGHT,
		UP + LEFT,
		DOWN + RIGHT ,
		DOWN + LEFT };

	//マスが空でなければ打てない。
	if (cells[move.drop_pos] != EMPTY) {
		return;
	}

	//現在の色を設定
	move.color = color_of_turn;

	//8方向石が挟まれているかを確認
	for (int i = 0; i < countof(directions); i++) {
		
		//現在の方向がひっくり返せない場合は元に戻すためにひっくり返すのが確定した
		//石の数を覚えておく。
		int pre_rev_pos_count = move.rev_pos_count;

		//まずうった石の隣のマスに注目する。
		int pos = move.drop_pos;
		pos += directions[i];
		
		while (cells[pos] == -color_of_turn) {
			//反対の色の石が続いていれば仮にひっくり返す位置に追加する。
			move.AddRevpos(pos);
			//隣の石に移動
			pos += directions[i];
			//最後が同じ色の石でなければ挟まれていない。
			if (cells[pos] == WALL || cells[pos] == EMPTY) {
				//仮にひっくり返る石に追加したものをキャンセルする。
				move.rev_pos_count = pre_rev_pos_count;
			}
		}
	}
}

Board::Board()
{
	const int x_of_left = 0;
	const int x_of_right = COL_MEM_SIZE - 1;
	const int y_of_top = 0;
	const int y_of_bottom = (ROW_MEM_SIZE - 1) * COL_MEM_SIZE;

	//右と左を壁にする。
	for (int y = 0; y < CELLS_COUNT; y += COL_MEM_SIZE) {
		cells[x_of_left + y] = WALL;
		cells[x_of_right + y] = WALL;
	}

	//上と下を壁にする。
	for (int x = 1; x <= COL_SIZE; x++) {
		cells[x + y_of_top] = WALL;
		cells[x + y_of_bottom] = WALL;
	}


	//なにもおいてない状態にする。
	for (int y = COL_MEM_SIZE; y < CELLS_COUNT - COL_MEM_SIZE; y+= COL_MEM_SIZE) {
		for (int x = 1; x <= COL_SIZE; x++) {
			cells[x + y] = EMPTY;	
		}
	}

	//４つの石を初期配置する。
	cells[position(4, 4)] = WHITE;
	cells[position(5, 5)] = WHITE;
	cells[position(4, 5)] = BLACK;
	cells[position(5, 4)] = BLACK;

	//初手にする。
	turn_count = 0;
	color_of_turn = BLACK;
	
	//手を生成
	GenerateMoves();
}


Board::~Board()
{
}
