// OtheroView.cpp : implementation of the COtheroView class
//

#include "stdafx.h"
#include "Othero.h"

#include "OtheroDoc.h"
#include "OtheroView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// COtheroView

IMPLEMENT_DYNCREATE(COtheroView, CView)

BEGIN_MESSAGE_MAP(COtheroView, CView)
	//{{AFX_MSG_MAP(COtheroView)
	ON_WM_LBUTTONDOWN()
	ON_COMMAND(ID_START_BLACK, OnStartBlack)
	ON_COMMAND(ID_START_WHITE, OnStartWhite)
	ON_COMMAND(ID_START_KURO, OnStartKuro)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COtheroView construction/destruction

COtheroView::COtheroView()
{
	// TODO: add construction code here
	m_FlagInGame = FALSE;
	InitBoard();

}

void COtheroView::InitBoard()
{
	int x, y;
	for(x = 0; x < MASU_NUM; x++){
		for(y = 0; y < MASU_NUM; y++){
			m_Board[x][y] = BLANK;
		}
	}
	m_Board[3][3] = m_Board[4][4] = BLACK_STONE;
	m_Board[3][4] = m_Board[4][3] = WHITE_STONE;

	m_FlagForWhite = FALSE;
	m_PutNumber = 0;
}

COtheroView::~COtheroView()
{
}

BOOL COtheroView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// COtheroView drawing

void COtheroView::OnDraw(CDC* pDC)
{
	COtheroDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	DrawBoard(pDC);
}

void COtheroView::DrawBoard(CDC* pDC)
{
	int x, y;
	CBrush gray_brush, black_brush, white_brush;
	white_brush.CreateStockObject(WHITE_BRUSH);
	gray_brush.CreateSolidBrush(RGB(200, 200, 200));
	black_brush.CreateSolidBrush(RGB(0 , 0, 0) );
	pDC->SelectObject(&gray_brush);

	for(x = 0; x < MASU_NUM; x++){
		for(y = 0; y < MASU_NUM; y++){
			pDC->SelectObject(&gray_brush);
			pDC->Rectangle(x * MASU_SIZE, y * MASU_SIZE,
							(x + 1) * MASU_SIZE - 1, (y + 1) * MASU_SIZE - 1);
			if(m_Board[x][y] == BLANK){
				continue;
			}else if (m_Board[x][y] == BLACK_STONE){
				pDC->SelectObject(&black_brush);
			}else{
				pDC->SelectObject(&white_brush);
			}
			pDC->Ellipse(x * MASU_SIZE + 3, y * MASU_SIZE + 3,
					(x + 1) * MASU_SIZE -4, (y + 1) * MASU_SIZE -4);
		}
	}
	pDC->SelectObject(&white_brush);
}
/////////////////////////////////////////////////////////////////////////////
// COtheroView diagnostics

#ifdef _DEBUG
void COtheroView::AssertValid() const
{
	CView::AssertValid();
}

void COtheroView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

COtheroDoc* COtheroView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(COtheroDoc)));
	return (COtheroDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// COtheroView message handlers

void COtheroView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if (m_FlagInGame == TRUE && m_FlagForPlayer == m_FlagForWhite){
		int x, y;
		x = point.x / MASU_SIZE;
		y = point.y / MASU_SIZE;

		if ( CanDropDown(x, y)) {
			Undo undo(x, y);
			DropDownStone(&undo);
			m_PutNumber++;
			CDC* pDC = GetDC();
			DrawBoard(pDC);
			ReleaseDC(pDC);
			m_FlagForPlayer = FALSE;
		}
	}
	
	End();
	if(m_FlagInGame)ComputeAI();
	

	
	CView::OnLButtonDown(nFlags, point);
}

BOOL COtheroView::CanDropDown(int x, int y)
{
	if (x < 0 || MASU_NUM <= x || y < 0 || MASU_NUM <= y) {
		return FALSE;
	}
	if (m_Board[x][y] != BLANK){
		return FALSE;
	}
	if (CanDropDown(x, y, 1, 0)){
		return TRUE;
	}
	if (CanDropDown(x, y, 0, 1)){
		return TRUE;
	}
	if (CanDropDown(x, y, -1, 0)){
		return TRUE;
	}
	if (CanDropDown(x, y, 0, -1)){
		return TRUE;
	}
	if (CanDropDown(x, y, 1, 1)){
		return TRUE;
	}
	if (CanDropDown(x, y, -1, -1)){
		return TRUE;
	}
	if (CanDropDown(x, y, -1, 1)){
		return TRUE;
	}
	if (CanDropDown(x, y, 1, -1)){
		return TRUE;
	}
	return FALSE;
}

BOOL COtheroView::CanDropDown(int x, int y, int vect_x, int vect_y){
	int put_stone;
	if (m_FlagForWhite){
		put_stone = WHITE_STONE;
	} else {
		put_stone = BLACK_STONE;
	}
	x += vect_x;
	y += vect_y;
	if(x < 0 || MASU_NUM <= x || y < 0 || MASU_NUM <= y){
		return FALSE;
	}
	if( m_Board[x][y] == put_stone){
		return FALSE;
	}
	if( m_Board[x][y] == BLANK)
	{
		return FALSE;
	}
	x += vect_x;
	y += vect_y;
	while(0 <= x && x < MASU_NUM && 0 <= y && y < MASU_NUM)
	{
		if( m_Board[x][y] == BLANK ){
			return FALSE;
		}
		if( m_Board[x][y] == put_stone ){
			return TRUE;
		}
		x += vect_x;
		y += vect_y;
	}
	return FALSE;
}

void COtheroView::DropDownStone(Undo *undo)
{
	int stone;
	if (m_FlagForWhite){
		stone = WHITE_STONE;
	}else {
		stone = BLACK_STONE;
	}
	m_Board[undo->x][undo->y] = stone;
	Reverse(undo);
	m_FlagForWhite = ! m_FlagForWhite;
}

void COtheroView::Reverse(Undo* undo)
{
	int x = undo->x;
	int y = undo->y;

	if(CanDropDown(x, y, 0, 1)){
		Reverse(undo, 0, 1);
	}
	if(CanDropDown(x, y, 1, 0)){
		Reverse(undo, 1, 0);
	}
	if(CanDropDown(x, y, 0, -1)){
		Reverse(undo, 0, -1);
	}
	if(CanDropDown(x, y, -1, 0)){
		Reverse(undo, -1, 0);
	}
	if(CanDropDown(x, y, 1, 1)){
		Reverse(undo, 1, 1);
	}
	if(CanDropDown(x, y, 1, -1)){
		Reverse(undo, 1, -1);
	}
	if(CanDropDown(x, y, -1, -1)){
		Reverse(undo, -1, -1);
	}
	if(CanDropDown(x, y, -1, 1)){
		Reverse(undo, -1, 1);
	}
	
}

void COtheroView::Reverse(Undo* undo, int vect_x, int vect_y)
{
	int x = undo->x;
	int y = undo->y;

	int stone;
	if (m_FlagForWhite){
		stone = WHITE_STONE;
	}else {
		stone = BLACK_STONE;
	}

	x += vect_x;
	y += vect_y;
	while(m_Board[x][y] != stone){
		m_Board[x][y] = stone;
		undo->AddPos(x, y);
		x += vect_x;
		y += vect_y;
	}
}

void COtheroView::DoUndo(Undo undo){
	for(int i = 0; i < undo.pointer; i++){
		int x = undo.position[i] % MASU_NUM;
		int y = undo.position[i] / MASU_NUM;
		m_Board[x][y] *= -1;
	}
	m_Board[undo.x][undo.y] = BLANK;
	m_FlagForWhite = ! m_FlagForWhite;
}

int COtheroView::CountStone(int stone)
{
	int x, y, count = 0;
	for(x = 0; x < MASU_NUM; x++){
		for(y = 0; y < MASU_NUM; y++){
			if(m_Board[x][y] == stone){
				count++;
			}
		}
	}
	return count;
}

void COtheroView::End()
{
	if (m_PutNumber == END_NUMBER)
	{
		int num;
		if(m_FlagForPlayer){
			num = CountStone(WHITE_STONE);
		}else{
			num = CountStone(BLACK_STONE);
		}
		if(num > (double)(m_PutNumber + 4) / 2){
			MessageBox("You Win!");
		}else if(num < (double)(m_PutNumber + 4) / 2){
			MessageBox("You Lose!");
		}else {
			MessageBox("Draw Game!");
		}
		m_FlagInGame = FALSE;
	}
}

void COtheroView::OnStartWhite() 
{
	m_FlagInGame = TRUE;
	m_FlagForPlayer = TRUE;
	InitBoard();

	CDC* pDC = GetDC();
	DrawBoard(pDC);
	ReleaseDC(pDC);	
	ComputeAI();

}

void COtheroView::OnStartKuro() 
{
	m_FlagInGame = TRUE;
	m_FlagForPlayer = FALSE;
	InitBoard();

	CDC* pDC = GetDC();
	DrawBoard(pDC);
	ReleaseDC(pDC);

	
}
void COtheroView::OnStartBlack() 
{
	m_FlagInGame = TRUE;
	m_FlagForPlayer = FALSE;
	InitBoard();

	CDC* pDC = GetDC();
	DrawBoard(pDC);
	ReleaseDC(pDC);
	
}

int COtheroView::MinMax(BOOL Flag, int lv, BOOL Put)
{
	int value, temp, x, y, vest_x, vest_y;
	if(lv == 0)return ValueBoard();
	if(Flag){
		value = -9999;
	}else{
		value = 9999;
	}
	for(x = 0; x < MASU_NUM; x++){
		for(y = 0; y < MASU_NUM; y++){
			if(CanDropDown(x,y)){
				Undo undo(x, y);
				DropDownStone(&undo);
				temp = MinMax(!Flag, lv - 1, TRUE);
				DoUndo(undo);
				if( (Flag && temp > value) || (!Flag && temp < value)){
					value = temp;
					vest_x = x;
					vest_y = y;
				}
			}
		}
	}
	if (lv == m_SearchLv){
		return vest_x + vest_y * MASU_NUM;
	}else if(value != 9999 && value != -9999){
		return value;
	}else if(!Put){
		return ValueBoard();
	}else{
		return MinMax(!Flag, lv - 1, FALSE);
	}
}

	
void COtheroView::ComputeAI()
{
	int x, y;
	y = MinMax(TRUE, m_SearchLv = SEARCH_LV, TRUE);
	if (0 > y || y >= MASU_NUM * MASU_NUM){
		return;
	}
	x = y % MASU_NUM;
	y = y / MASU_NUM;
	Undo undo(x, y);
	DropDownStone(&undo);
	m_PutNumber++;

	CDC* pDC = GetDC();
	DrawBoard(pDC);
	ReleaseDC(pDC);

	for(x = 0; x < MASU_NUM * MASU_NUM; x++){
		if(m_PutNumber == 60){
			break;
		}
		if(CanDropDown(x % MASU_NUM, x / MASU_NUM)){
			break;
		}
		if(x == MASU_NUM * MASU_NUM - 1)
		{
			ComputeAI();
		}
	}
}

int COtheroView::ValueBoard()
{
	int value = ValueBoardPlace();
/*
	if (m_PutNumber <= MIDDLE_NUM)
	{
		value += ValueBoardPlace();
		value += ValueBoardDropDownNum();
	}else if(m_PutNumber <= FINISH_NUM)
	{
		value += ValueBoardPlace();
		value += ValueBoardDropDownNum();
	}else {
		value += ValueBoardNumber();
	}
*/
	if( !m_FlagForPlayer ){
		return value;
	}else {
		return -value;
	}
}

int COtheroView::ValueBoardPlace()
{
	int x, y, value;
	for(x = 0; x < MASU_NUM; x++){
		for(y = 0; y < MASU_NUM; y++){
			value += m_Board[x][y] * ValuePlace[x][y];
		}
	}
	return -value;
}

int COtheroView::ValueBoardDropDownNum()
{
		int x, y, value;
	for(x = 0; x < MASU_NUM; x++){
		for(y = 0; y < MASU_NUM; y++){
			if(CanDropDown(x, y)){
				value += 1;
			}
		}
	}
	if ( m_FlagForWhite == ! m_FlagForPlayer){
		return 3 * value;
	}else{
		return -3 * value;
	}
}

int COtheroView::ValueBoardNumber(){
	int x, y, value;
	for(x = 0; x < MASU_NUM; x++){
		for(y = 0; y < MASU_NUM; y++){
			value += m_Board[x][y];
		}
	}
	return -value;
}