Click here to Skip to main content
15,892,809 members
Articles / Artificial Intelligence

Nura Othello - A WTL Based Board Game

Rate me:
Please Sign up or sign in to vote.
4.40/5 (14 votes)
6 Feb 2007CPOL23 min read 79.6K   2.3K   29  
An example of using the WTL library in an artificial intelligence game.
///////////////////////////////////////////////////////////////////////////////
// OthelloCore.cpp Ver. 1.6
// Programmer: PARK Youngho
///////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <cstdlib>
#include <cassert>
#include <ctime>
#include "OthelloCore.h"

OthelloCore::OthelloCore (const char firstPlayer)
{
	m_pMemento = new OthelloMemento(this);
	assert(m_pMemento);
	for (char i = 0; i < OTHELLO_WIDTH; i++)
		C[i] = i+1;

#ifdef OTHELLO_RANDOM_SEED
	srand(clock());
#endif

	Initialize(firstPlayer);
}

OthelloCore::OthelloCore (int diag, const char firstPlayer)
{
	m_pMemento = new OthelloMemento(this);
	assert(m_pMemento);
	for (char i = 0; i < OTHELLO_WIDTH; i++)
		C[i] = i+1;

#ifdef OTHELLO_RANDOM_SEED
	srand(clock());
#endif

	Initialize(diag, firstPlayer);
}

OthelloCore::OthelloCore (OthelloCore* that)
{
	assert(that);
	memcpy((void*) m_Board, (void*) that->m_Board, sizeof m_Board);
	memcpy(C, that->C, sizeof C);
	m_Cur		= that->m_Cur;
	m_bOrder	= that->m_bOrder;
	m_First		= that->m_First;
	m_Diag		= that->m_Diag;
	m_pMemento	= that->m_pMemento->Clone(this);
}

OthelloCore::~OthelloCore (void)
{
	if (m_pMemento)
        delete m_pMemento;
}

void OthelloCore::Initialize (int diag, const char firstPlayer)
{
	m_First		= firstPlayer;
	m_Cur		= 0;
	InitBoard(diag);
	InitPriority();
	SwapIndex();
}

void OthelloCore::InitBoard (int diag)
{
	memset((void*) m_Board, BLANK, sizeof m_Board);
	m_bOrder	= (m_First == PLAYER1);
	m_Diag		= (char) (diag % 8);

	switch (m_Diag)
	{
	case 0:
	case 6:
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_WIDTH / 2]	= PLAYER2;
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_MARGIN / 2]	= PLAYER1;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_WIDTH / 2]	= PLAYER1;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_MARGIN / 2]	= PLAYER2;
		m_pMemento->Initialize(OTHELLO_WIDTH / 2, OTHELLO_MARGIN / 2,
							OTHELLO_MARGIN / 2, OTHELLO_WIDTH / 2, PLAYER1);
		m_pMemento->Initialize(OTHELLO_WIDTH / 2, OTHELLO_WIDTH / 2,
							OTHELLO_MARGIN / 2, OTHELLO_MARGIN / 2, PLAYER2);
		break;
	case 1:
	case 7:
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_WIDTH / 2]	= PLAYER1;
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_MARGIN / 2]	= PLAYER2;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_WIDTH / 2]	= PLAYER2;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_MARGIN / 2]	= PLAYER1;
		m_pMemento->Initialize(OTHELLO_WIDTH / 2, OTHELLO_WIDTH / 2,
							OTHELLO_MARGIN / 2, OTHELLO_MARGIN / 2, PLAYER1);
		m_pMemento->Initialize(OTHELLO_WIDTH / 2, OTHELLO_MARGIN / 2,
							OTHELLO_MARGIN / 2, OTHELLO_WIDTH / 2, PLAYER2);
		break;
	case 2:
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_WIDTH / 2]	= PLAYER1;
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_MARGIN / 2]	= PLAYER1;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_WIDTH / 2]	= PLAYER2;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_MARGIN / 2]	= PLAYER2;
		m_pMemento->Initialize(OTHELLO_WIDTH / 2, OTHELLO_WIDTH / 2,
							OTHELLO_WIDTH / 2, OTHELLO_MARGIN / 2, PLAYER1);
		m_pMemento->Initialize(OTHELLO_MARGIN / 2, OTHELLO_WIDTH / 2,
							OTHELLO_MARGIN / 2, OTHELLO_MARGIN / 2, PLAYER2);
		break;
	case 3:
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_WIDTH / 2]	= PLAYER2;
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_MARGIN / 2]	= PLAYER2;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_WIDTH / 2]	= PLAYER1;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_MARGIN / 2]	= PLAYER1;
		m_pMemento->Initialize(OTHELLO_MARGIN / 2, OTHELLO_WIDTH / 2,
							OTHELLO_MARGIN / 2, OTHELLO_MARGIN / 2, PLAYER1);
		m_pMemento->Initialize(OTHELLO_WIDTH / 2, OTHELLO_WIDTH / 2,
							OTHELLO_WIDTH / 2, OTHELLO_MARGIN / 2, PLAYER2);
		break;
	case 4:
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_WIDTH / 2]	= PLAYER1;
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_MARGIN / 2]	= PLAYER2;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_WIDTH / 2]	= PLAYER1;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_MARGIN / 2]	= PLAYER2;
		m_pMemento->Initialize(OTHELLO_WIDTH / 2, OTHELLO_WIDTH / 2,
							OTHELLO_MARGIN / 2, OTHELLO_WIDTH / 2, PLAYER1);
		m_pMemento->Initialize(OTHELLO_WIDTH / 2, OTHELLO_MARGIN / 2,
							OTHELLO_MARGIN / 2, OTHELLO_MARGIN / 2, PLAYER2);
		break;
	case 5:
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_WIDTH / 2]	= PLAYER2;
		m_Board[OTHELLO_WIDTH / 2][OTHELLO_MARGIN / 2]	= PLAYER1;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_WIDTH / 2]	= PLAYER2;
		m_Board[OTHELLO_MARGIN / 2][OTHELLO_MARGIN / 2]	= PLAYER1;
		m_pMemento->Initialize(OTHELLO_WIDTH / 2, OTHELLO_MARGIN / 2,
							OTHELLO_MARGIN / 2, OTHELLO_MARGIN / 2, PLAYER1);
		m_pMemento->Initialize(OTHELLO_WIDTH / 2, OTHELLO_WIDTH / 2,
							OTHELLO_MARGIN / 2, OTHELLO_WIDTH / 2, PLAYER2);
		break;
	}
}

void OthelloCore::SwapIndex (void)
{
	int		v1, v2;
	char	temp;

	for (int i = 0; i < OTHELLO_WIDTH + (OTHELLO_WIDTH / 2); i++)
	{
		v1		= rand() % OTHELLO_WIDTH;
		v2		= rand() % OTHELLO_WIDTH;
		temp	= C[v1];
		C[v1]	= C[v2];
		C[v2]	= temp;
	}
}

void OthelloCore::InitPriority (void)
{
}

int OthelloCore::Evaluate (int x, int y, const int player)
{
	if (	(x < 1) || (x > OTHELLO_WIDTH)
		||	(y < 1) || (y > OTHELLO_WIDTH)
		||	(BLANK != m_Board[x][y]) )
		return 0;

	int		ret = 0;
	int		opponent = (PLAYER1 == player) ? PLAYER2 : PLAYER1;

	for (int dirx = -1; dirx <= 1; dirx++)
	{
		for (int diry = -1; diry <= 1; diry++)
		{
			int		xx, yy, cnt;

			for (xx = x + dirx, yy = y + diry, cnt = 0;
					m_Board[xx][yy] == opponent;
					cnt++, xx += dirx, yy += diry);

			if ( cnt && (player == m_Board[xx][yy]) )
				ret += cnt;
		}
	}

	return ret;
}

bool OthelloCore::PutStone (int x, int y, const int player, bool bWithdraw)
{
	if (	(x < 1) || (x > OTHELLO_WIDTH)
		||	(y < 1) || (y > OTHELLO_WIDTH)
		||	(BLANK != m_Board[x][y]) )
		return false;

	bool	bPut = false;
	int		opponent = (PLAYER1 == player) ? PLAYER2 : PLAYER1;

	for (int dirx = -1; dirx <= 1; dirx++)
	{
		for (int diry = -1; diry <= 1; diry++)
		{
			int		xx, yy, cnt;

			for (xx = x + dirx, yy = y + diry, cnt = 0;
					m_Board[xx][yy] == opponent;
					cnt++, xx += dirx, yy += diry);

			if ( cnt && (player == m_Board[xx][yy]) )
			{
				bPut = true;
				for (xx -= dirx, yy -= diry; cnt; cnt--, xx -= dirx, yy -= diry)
					m_Board[xx][yy] = (char) player;
			}
		}
	}
	if (bPut)
	{
		m_Board[x][y]	= (char) player;
		m_bOrder		= !m_bOrder;
		Reorder(x, y);
		if (!bWithdraw)
			m_pMemento->Push(x, y, player);

		m_Cur++;
	}

	return bPut;
}

bool OthelloCore::PutFirst (void)
{
	if (WhoFirst() != PLAYER1)
		return false;

	int		x, y;

	if (SeekBestPoint (&x, &y, PLAYER1))
		PutStone(x, y, PLAYER1);

	return true;
}

bool OthelloCore::Withdraw (void)
{
	if (1 >= m_Cur)
		return false;

	int		cur = m_Cur - 2;
	Initialize(m_Diag, m_First);

	for (int i = 0; i < cur; i++)
	{
		int		x, y, player;
		m_pMemento->GetXY(i, &x, &y, &player);
		PutStone(x, y, player, true);
	}

	return true;
}

bool OthelloCore::Restore (void)
{
	if (m_pMemento->GetMax() <= m_Cur)
		return false;

	for (int i = 0; i < 2; i++)
	{
		int		x, y, player;
		m_pMemento->GetXY(m_Cur, &x, &y, &player);
		PutStone(x, y, player, true);
	}

	return true;
}

char OthelloCore::GetBoard (int x, int y)
{
	if ( (x > 0) && (x <= OTHELLO_WIDTH) && (y > 0) && (y <= OTHELLO_WIDTH) )
		return m_Board[x][y];

	return OUTOFBOARD;
}

int OthelloCore::WhoWin (int* pPlayer1, int* pPlayer2)
{
	int		cnt1 = 0, cnt2 = 0;
	for (int x = 1; x <= OTHELLO_WIDTH; x++)
	{
		for (int y = 1; y <= OTHELLO_WIDTH; y++)
		{
			if		(PLAYER1 == m_Board[x][y])
				cnt1++;
			else if (PLAYER2 == m_Board[x][y])
				cnt2++;
		}
	}
	if (pPlayer1)
		*pPlayer1 = cnt1;
	if (pPlayer2)
		*pPlayer2 = cnt2;

	if		(cnt1 > cnt2)
		return PLAYER1;
	else if (cnt1 < cnt2)
		return PLAYER2;
	else	// if (cnt1 == cnt2)
		return BLANK;
}

bool OthelloCore::IsEnded (void)
{
	if (60 <= m_Cur)
		return true;

	int		player1, player2;

	WhoWin(&player1, &player2);

	return !(player1 && player2);
}

bool OthelloCore::Trace (int *px, int *py, int step)
{
	return m_pMemento->GetXY(m_Cur + step - 1, px, py);
}

#ifdef OTHELLO_IQ_TEST
int OthelloCore::Compete (OthelloCore* pOthello1, OthelloCore* pOthello2,
							int* pPlayer1, int* pPlayer2)
{
	assert(pOthello1 && pOthello2);
	if (	(pOthello1->m_Diag != pOthello2->m_Diag)
		|| (PLAYER1 != pOthello1->m_First)
		|| (PLAYER1 != pOthello2->m_First) )
		return OUTOFBOARD;

	int		x, y;

	do
	{
		if (pOthello1->SeekBestPoint(&x, &y, PLAYER1))
		{
			pOthello1->PutStone(x, y, PLAYER1);
			pOthello2->PutStone(x, y, PLAYER1);
		}
		else if (m_pOthello1->IsEnded())
		{
			break;
		}
		else
		{	
			m_pOthello1->Pass();
			m_pOthello2->Pass();
		}

		if (pOthello2->SeekBestPoint(&x, &y, PLAYER2))
		{
			pOthello1->PutStone(x, y, PLAYER2);
			pOthello2->PutStone(x, y, PLAYER2);
		}
		else if (m_pOthello2->IsEnded())
		{
			break;
		}
		else
		{
			m_pOthello1->Pass();
			m_pOthello2->Pass();
		}
	} while (true);

	return pOthello1->WhoWin(pPlayer1, pPlayer2);
}

void OthelloCore::Simulate (int step)
{
	if (step < 0)
		step = 60;

	for (int i = 1; i <= step; i++)
	{
		int		stone = WhoseTurn();
		int		x, y;
		if (SeekBestPoint(&x, &y, stone))
			PutStone(x, y, stone);
		else if (IsEnded())
			break;
		else
			Pass();
	}
}


int OthelloCore::WhoAdvantageous (int* pPlayer1, int* pPlayer2)
{
	return WhoWin(pPlayer1, pPlayer2);
}
#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Korea (Republic of) Korea (Republic of)
I like programming.
I am teaching at AUCA (American University of Central Asia) now.

Comments and Discussions