Click here to Skip to main content
15,867,568 members
Articles / Artificial Intelligence
Article

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.1K   2.3K   29   15
An example of using the WTL library in an artificial intelligence game.

Image 1

Contents

  1. Introduction
    1. The name of Nura Othello
    2. The rules of Nura Othello
    3. The features of Nura Othello
    4. The usage of Nura Othello
  2. Background
  3. The source code
  4. Environment
  5. Using the code
    1. Entire Structure
    2. The Class CMainDlg
    3. The Class OthelloWindowWTL
    4. The user-defined Message NM_OTHELLO (= UM_OTHELLO) of OthelloWindowWTL
    5. The Classes OthelloCore, OthelloCore0, OthelloCore1, OthelloCore2, and OthelloCore3
      1. Inheritance Structure
      2. The strategies of artificial intelligence
        1. The strategy of OthelloCore
        2. The strategy of OthelloCore0
        3. The strategy of OthelloCore1
        4. The strategy of OthelloCore2
        5. The strategy of OthelloCore3
  6. Points of Interest
  7. Othello Customizer
  8. Acknowledgement

Introduction

The name of Nura Othello

Nura Othello is a computer board game that a user can play with a computer. The Othello game is sometimes called Reversi as well. Nura is my wife's name. So, I named my program Nura Othello. Nur means light in Arabic, and -a is a feminine suffix, so that Nura can mean bright lady. It is a very popular Arabic name of women in Middle East.

The rules of Nura Othello

  1. Nura Othello is played on a 8 X 8 board. It looks like a chess board.
  2. Players shall put their stones on a square cell, not on a line or on a cross point of the lines.
  3. The game begins with putting two stones for each player in the center of the board.
  4. If my stones surround the opponent's stone(s) horizontally, vertically, or diagonally, the opponent's surrounded stone(s) shall change into my stone(s).
  5. Players can put their stones only on the place where they can surround their opponent's stone(s);
  6. Players shall put their stones alternatively.
  7. During the game, if any one of the players does not have any place to put his/her/its stone, his/her/its turn shall come to the other.
  8. Eventually, the player who has more stones will win the game.
  9. However, during the game, if both players have no place to put his/her/its stone, the game shall be ended and the player who has more stones will win the game.

The features of Nura Othello

  1. It automatically detects the language of Windows, and shows all the instructions in either Korean or English. If your Windows is Korean Windows, it will have Korean mode, but if it is other language Windows, it will have English mode. However, you can customize Nura Othello into your language by using NuraOthell.ini. You can generate NuraOthell.ini by using OthelloCustomizer.exe. I will introduce OthelloCustomizer.exe later.
  2. According to the IQ of the artificial intelligence required from the game, a user can choose from level 0 to level 3.
  3. At the start of the game, the initial positions of the four stones will be determined randomly. It has six possibilities, as follows:

    Screenshot - NuraOthello2.gif Screenshot - NuraOthello3.gif Image 4

    Image 5 Image 6 Image 7

  4. It shows who is winning at the moment, by a graph.
  5. It has the option to let the computer put his stone first or second.
  6. It has the option to set time limit before a user will lose the game if the user does not put his or her stone.
  7. Before you start the game, if you press the key 'F1', an About-message box will pop up. You can see simple information about Nura Othello there.

The Usage of Nura Othello

  1. To start the game, click the button "Start".
  2. During the game, if you want to cancel the game, click the button "Cancel".
  3. Before the game starts, if you want your computer to put a stone first, check the button "Com. First".
  4. Before the game starts, if you want to enjoy the stress of time limitation, check the button "Time Limit".
  5. Before the game starts, you can choose the IQ of the artificial intelligence of Nura Othello. Level 3 is the most difficult, and level 0 is the easiest.

Background

It includes three things: artificial intelligence engines, a control-like window, and a skin window. I will give some brief descriptions about those things in this article. I used some design patterns: the Memento Pattern and the Bridge Pattern (exactly speaking, a modified version of the Bridge Pattern), but I would not explain about design patterns here. It uses multithreading and critical sections for synchronization. If you do not know much about critical sections, you can get some idea about critical sections from here. In addition, you can easily search Google for the strategies of the Othello game.

The Source Code

This source code uses the WTL library. For comparison, I also redundantly developed it with MFC. If you also know MFC well, you can compare the WTL source with the MFC source. However, I would not explain about the MFC source code since the MFC source code is so similar to the WTL source code that you can easily understand the MFC source code if you understand the WTL source code. The source code includes six projects: OthelloCore, OthelloWindowWTL, OthelloWindowMFC, NuraOthello (in the OthelloWTL folder), OthelloMFC, and OthelloCustomizer. The project OthelloCore is the library of the Othello engine (including the artificial intelligence). The projects OthelloWindowWTL and OthelloWindowMFC are the control-like libraries of the Othello window for WTL and MFC, respectively. The projects NuraOthello and OthelloMFC are the executable projects which are written in WTL and MFC, respectively. But, they do not use the library of Othello window but use the sources of Othello window and Othello core directly. Finally, the project OthelloCustomizer is the executable project which is written in WTL.

Environment

Nura Othello was created with VC++ .NET 2003 Standard Edition SP1 (hereinafter, referred to as VC++ 7.1) with WTL 8.0. You can get WTL 8.0 from here if the website is not changed. It was mainly tested under Windows XP SP2 and Windows 2000 SP4, but I found that it did not work under Windows 98 SE. To compile the source code, you need to have WTL installed. Also, it can be compiled with VC++ .NET 2005 Express Edition (hereinafter, referred to as VC++ 8.0X). Of course, you have to take some steps before compiling it. It is disclosed here about using VC++ 8.0X for Windows programming, and here about WTL installation for VC++ 8.0X. To make it be able to be compiled with VC++ 8.0X which uses ATL 3.0, I made ATLVersion.h and included it in stdafx.h. Othello.sln is for VC++ 7.1 while Othello2005.sln is for VC++ 8.0X. OthelloWTL.vcproj is for VC++ 7.1 while OthelloWTL2005.vcproj is for VC++ 8.0X. All the file name conventions for solution files (*.sln) and project files (*.vcproj) are like above examples.

Using the Code

Entire Structure

I have mentioned that Nura Othello consists of three parts: artificial intelligence engines, a control-like window, and a skin window. The skin window is a dialog-based framework itself, and contains the control-like window as its child window. The skin window is implemented by a class CMainDlg. The control-like window is the Othello game window itself, and is a child window of the skin window. The reason why I call this window control-like window is that this window is not actually a control but it functions as a control. The control-like window contains the artificial intelligence engines, and is implemented by the class OthelloWindowWTL. The artificial intelligence engines are implemented by the classes OthelloCore, OthelloCore0, OthelloCore1, OthelloCore2, and OthelloCore3.

The Class CMainDlg

The class CMainDlg is provided by the WTL-App Wizard, and I coded on it. All the layout is made with a resource editor of VC++ 7.1. It receives the user-defined message UM_OTHELLO from OthelloWindowWTL. Its member function OnOthelloMessage will deal with the message UM_OTHELLO. Whenever it receives UM_OTHELLO, it changes the progress bar which shows who is winning, and the time graph which shows how much time remains if the time limitation option is on. The following code is related with the processing of the user-defined message UM_OTHELLO.

C++
LRESULT CMainDlg::OnOthelloMessage (UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (wParam)
    {
    case ON_MYSTONE:    OnOthelloMyStone();          break;
    case ON_YOURSTONE:  OnOthelloYourStone();        break;
    case ON_PASS:       OnOthelloPass(lParam);       break;
    case ON_FINISH:     OnOthelloFinish(lParam);     break;
    case ON_NOPLACE:    OnOthelloNoPlace(lParam);    break;
    }

    return 0;
}

void CMainDlg::OnOthelloUpdate (void)
{
    int     player[2], sum;
    TCHAR   str[15];

    m_pOthello->WhoWin(&player[0], &player[1]);
    sum = player[0] + player[1];
    m_Progress.SetRange(0, sum);
    m_Progress.SetPos(player[1]);
    for (int i = 0; i < 2; i++)
    {
        _stprintf(str, _T("%s: %d"), m_strPlayer[i], player[i]);
        m_Player[i].SetWindowText(str);
    }
}

void CMainDlg::OnOthelloMyStone (void)
{
    OnOthelloUpdate();
    if (!m_bTimeLimit)
        return;

    m_CountDown = LIMITATION;
    m_Elapsed.SetPos(LIMITATION);
    KillTimer(m_pOthello->GetStep() - 1);
    SetTimer(m_pOthello->GetStep(), TIMESTEP, NULL);
}

void CMainDlg::OnOthelloYourStone (void)
{
    OnOthelloMyStone();
}

void CMainDlg::OnOthelloPass (LPARAM lParam)
{
    m_CountDown = LIMITATION;
    m_Elapsed.SetPos(LIMITATION);
    KillTimer(m_pOthello->GetStep() - 1);

    switch (lParam)
    {
    case PLAYER1:    MessageBox(m_strWait);    break;
    case PLAYER2:    MessageBox(m_strPass);    break;
    }

    m_CountDown = LIMITATION;
    m_Elapsed.SetPos(LIMITATION);
    SetTimer(m_pOthello->GetStep(), TIMESTEP, NULL);
}

void CMainDlg::OnOthelloFinish (void)
{
    if (m_bTimeLimit)
        KillAllTimers();

    if (lParam)
    {
        CString     strResult, str;
        int         player1     = GETSCORE1(lParam);
        int         player2     = GETSCORE2(lParam);

        if      (player1 > player2)     strResult = m_strLose;
        else if (player1 < player2)     strResult = m_strWin;
        else                            strResult = m_strDraw;

        str.Format(strResult, player2, player1);
        MessageBox(str);
    }
}

void CMainDlg::OnOthelloNoPlace (LPARAM lParam)
{
    int         player1     = GETSCORE1(lParam);
    int         player2     = GETSCORE2(lParam);
    CString     strResult   = m_strNoPlace;
    CString     str;

    strResult += _T("\n");
    if      (player1 > player2)     strResult += m_strLose;
    else if (player1 < player2)     strResult += m_strWin;
    else                            strResult += m_strDraw;

    str.Format(strResult, player2, player1);
    MessageBox(str);
}

It also receives instructions from users through push buttons, check buttons, and a combobox. You can also compile it as a single-thread version. To do so, uncomment the statements of line 54 in stdafx.h in the folder OthelloWTL, as follows:

C++
#define OTHELLO_NOT_THREAD 

I disabled the withdrawal function since it works very well on my computer but it works terribly on some other computers. I think that it is caused from some thread problem but, at the moment, I do not know the reason exactly. If you want to enable the withdrawal function, comment the statements of line 55 in stdafx.h in the folder OthelloWTL, as follows:

// #define NOTWITHDRAWAL

The Class OthelloWindowWTL

It uses two user-defined messages: NM_SELF and NM_OTHELLO (exactly speaking, m_Message or UM_OTHELLO, in this case). NM_SELF is only for internal use, while NM_OTHELLO is for external use only. OthelloWindowWTL sends NM_OTHELLO to CMainDlg whenever a stone is put. It will also send NM_OTHELLO to CMainDlg when the game is finished. To avoid message conflicts in CMainDlg, the constructor of OthelloWindowWTL can receive a different value of user-defined message of NM_OTHELLO as a parameter and save it on m_Message. OthelloWindowWTL is independent from CMainDlg in the sense that CProgressBarCtrl is independent from CMainDlg. The public member functions of OthelloWindowWTL are as follows:

class OthelloWindowWTL : public CWindowImpl<OthelloWindowWTL>
{
    ...
public:
    OthelloWindowWTL (UINT message = NM_OTHELLO, bool bAutoFinish = true);
    OthelloWindowWTL (UINT message, int lang, bool bAutoFinish);
    virtual ~OthelloWindowWTL ();
    ...
public:
    inline bool Start (void)        { return StartStop (true); }
    inline bool Stop (void)         { return StartStop (false); }
    inline void Initialize (void)   { Initialize(rand() % 8); }
    inline void Initialize (const char FirstPlayer, int IQ = OTHELLO_SMART)
        { Initialize(rand() % 8, FirstPlayer, IQ); }

    void Initialize (int diag, const char firstPlayer = PLAYER2, 
                     int IQ = OTHELLO_SMART);
    bool Withdraw (void);
    int WhoWin (int* pPlayer1 = 0, int* pPlayer2 = 0) const;
    int WhoseTurn (void) const;
    int GetStep (void) const;
    
    HWND Create (HWND hParentWnd, int x, int y, UINT nID);
    HWND Create (HWND hParentWnd, const POINT& pt, UINT nID);
    HWND Create (HWND hParentWnd, int x, int y, 
                 int nWidth, int nHeight, UINT nID);
    HWND Create (HWND hParentWnd, const RECT& rect, UINT nID);
    HWND Create (HWND hParentWnd, int x, int y, DWORD dwStyle, 
                 DWORD dwExStyle, UINT nID);
    HWND Create (HWND hParentWnd, const POINT& pt, 
                 DWORD dwStyle, DWORD dwExStyle, UINT nID);
    HWND Create (HWND hParentWnd, int x, int y, int nWidth, 
                 int nHeight, DWORD dwStyle, 
                 DWORD dwExStyle, UINT nID);
    HWND Create (HWND hParentWnd, const RECT& rect, 
                 DWORD dwStyle, DWORD dwExStyle, UINT nID);

    BOOL Move (int x, int y, BOOL bRepaint = TRUE);
    BOOL Move (POINT& pt, BOOL bRepaint = TRUE);
    BOOL Move (int x, int y, int nWidth, int nHeight, 
               BOOL bRepaint = TRUE);
    BOOL Move (RECT& rect, BOOL bRepaint = TRUE);
    ...
}

OthelloWindowWTL (UINT message = NM_OTHELLO, bool bAutoFinish = true);

  1. It is a constructor.
  2. The first parameter message is the message which OthelloWindowWTL will sent to the parent window. To avoid message conflict, you can give a different value for the message. The default is NM_OTHELLO.
  3. The second parameter is whether it deals with the end process by itself or not. If the second parameter bAutoFinish is set to be true, it would not send NM_OTHELLO (or the message you gave) to the parent window and it will deal with the end process. The default is true.
  4. Language will be automatically chosen according to the default language of Windows.

OthelloWindowWTL (UINT message, int lang, bool bAutoFinish);

  1. It is another constructor.
  2. The first and third parameters are the same as described above.
  3. The second parameter lang is for the language. If you set it to be LANG_KOREAN, it will use Korean regardless of the default language of Windows.

inline bool Start (void);

  1. It makes the Othello game start.
  2. The return value is true when the game starts, and is false when it fails.

inline bool Stop (void);

  1. It makes the Othello game stop. But, when the stones are being changed, it does not stop the game, and returns immediately without doing anything.
  2. The return value is true when the game stops, and is false when it fails.

void Initialize (int diag, const char firstPlayer = PLAYER2, int IQ = OTHELLO_SMART);

  1. It initializes the Othello game.
  2. The first parameter diag is the initial position of the four stones. It is as shown below, where blue is user's and red is computer's.
    Figure

    Image 8

    Image 9

    Image 10

    diag0 or 61 or 72
    Figure

    Image 11

    Image 12

    Image 13

    diag345
  3. The second parameter firstPlayer is the player who will put the stone first. If firstPlayer is PLAYER2, the user will put the stone first. If firstPlayer is PLAYER1, the computer will put the stone first. The default is PLAYER2.
  4. IQ is the IQ of artificial intelligence of Nura Othello. At the moment, IQ is set from 0 to 3. If IQ is set to 3, it will have the smartest IQ. If IQ is set to be 0, it will be stupidest. The higher the number is, the smarter the artificial intelligence is. The default is 3.

inline void Initialize ();

It is the same as Initialize(rand() % 8, PLAYER2, OTHELLO_SMART).

inline void Initialize (const char FirstPlayer, int IQ = OTHELLO_SMART);

It is the same as Initialize(rand() % 8, FirstPlayer, IQ).

bool Withdraw (void);

  1. It forcefully withdraws the computer's stone and then withdraws the user's stone. However, it has a bug. I do not know what is wrong.
  2. The return value is true when it succeeds, and false when it fails.

int WhoWin (int* pPlayer1 = 0, int* pPlayer2 = 0) const;

  1. It tells who is winning or has won.
  2. The return value is the winner. If it is PLAYER1, the computer is winning or has won. If it is PLAYER2, the user is winning or has won.
  3. The first parameter pPlayer1 is the pointer of an integer variable in which the score of the computer will be saved. If it is zero, it will be ignored.
  4. The second parameter pPlayer2 is the pointer of an integer variable in which the score of the user will be saved. If it is zero, it will be ignored.

int WhoseTurn (void) const;

  1. It tells whose turn it is next.
  2. The return value is the player who shall put his or her stone. If it is PLAYER1, it is the computer's turn. If it is PLAYER2, it is the user's turn.

int GetStep (void) const;

  • It tells the ordering number of the current step.
  • The return value is the ordering number of the current step.

HWND Create (HWND hParentWnd, const RECT& rect, DWORD dwStyle, DWORD dwExStyle, UINT nID);

  • It creates Othello control-like Window. Its window class name is OTHELLO_CLASS, which is defined as "Othello" for ASCII code, and L"Othello" for UNICODE.
  • The return value is the window handle to the Othello window.
  • The first parameter hParentWnd is the window handle to its parent window.
  • The second parameter rect is the reference to the rectangle of the Othello window.
  • The third parameter dwStyle is the window style of the Othello window.
  • The fourth parameter dwExStyle is the extended window style of the Othello window.
  • The fifth parameter nID is the ID given to the Othello window.

HWND Create (HWND hParentWnd, const POINT& pt, DWORD dwStyle, DWORD dwExStyle, UINT nID);

  • It creates the Othello control-like Window. Its window class name is OTHELLO_CLASS, which is defined as "Othello" for ASCII code, and L"Othello" for UNICODE.
  • The return value is the window handle to the Othello window.
  • The first parameter hParentWnd is the window handle to its parent window.
  • The second parameter pt is the reference to the left-top point of the Othello window. Its width and height will be both determined to be 400 pixels.
  • The third parameter dwStyle is the window style of the Othello window.
  • The fourth parameter dwExStyle is the extended window style of the Othello window.
  • The fifth parameter nID is the ID given to the Othello window.

HWND Create (HWND hParentWnd, const RECT& rect, UINT nID);

  • It creates the Othello control-like Window. Its window class name is OTHELLO_CLASS, which is defined as "Othello" for ASCII code, and L"Othello" for UNICODE.
  • The return value is the window handle to the Othello window.
  • The first parameter hParentWnd is the window handle to its parent window.
  • The second parameter rect is the reference to the rectangle of the Othello window.
  • The third parameter nID is the ID given to the Othello window.
  • The style and the extended style of the Othello window are both NULL, by default.

HWND Create (HWND hParentWnd, const POINT& pt, UINT nID);

  • It creates Othello control-like Window. Its window class name is OTHELLO_CLASS, which is defined as "Othello" for ASCII code, and L"Othello" for UNICODE.
  • The return value is the window handle to the Othello window.
  • The first parameter hParentWnd is the window handle to its parent window.
  • The second parameter pt is the reference to the left-top point of the Othello window. Its width and height will be both determined to be 400 pixels.
  • The third parameter nID is the ID given to the Othello window.
  • The style and the extended style of the Othello window are both NULL, by default.

BOOL Move (int x, int y, BOOL bRepaint = TRUE);

  • It moves the window to the specified position.
  • The return value is true if it succeeds, and false if it fails.
  • The first and second parameters x and y are the left-top position of the Othello window.
  • The third parameter bRepaint is related to whether the Othello window will be redrawn when it moves. If bRepaint is true, the Othello window will be redrawn. If bRepaint is false, the Othello window will not be redrawn. The default of bRepaint is true.
  • The width and height of the Othello window will be retained as before.

BOOL Move (POINT& pt, BOOL bRepaint = TRUE);

  • It moves the window to the specified position.
  • The return value is true if it succeeds, and false if it fails.
  • The first parameter pt is the left-top position of the Othello window.
  • The second parameter bRepaint is related to whether the Othello window will be redrawn when it moves. If bRepaint is true, the Othello window will be redrawn. If bRepaint is false, the Othello window will not be redrawn. The default of bRepaint is true.
  • The width and height of the Othello window will be retained as before.

BOOL Move (int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE);

  • It moves the window to the specified position.
  • The return value is true if it succeeds, and false if it fails.
  • The first, second, third, and fourth parameters x, y, nWidth, nHeight are the Othello window's position.
  • The fifth parameter bRepaint is related to whether the Othello window will be redrawn when it moves. If bRepaint is true, the Othello window will be redrawn. If bRepaint is false, the Othello window will not be redrawn. The default of bRepaint is true.

BOOL Move (RECT& rect, BOOL bRepaint = TRUE);

  • It moves the window to the specified position.
  • The return value is true if it succeeds, and false if it fails.
  • The first parameter rect is the reference to the Othello window's position.
  • The second parameter bRepaint is related to whether the Othello window will be redrawn when it moves. If bRepaint is true, the Othello window will be redrawn. If bRepaint is false, the Othello window will not be redrawn. The default of bRepaint is true.

The patterns of Create(...) and Move(...) are the same as those of Nura Tetris. Nura Tetris is posted here. I prefer these patterns of the functions Create(...) and Move(...).

The user-defined Message NM_OTHELLO (= UM_OTHELLO) of OthelloWindowWTL

The user-defined Message NM_OTHELLO (= UM_OTHELLO in this case) has WPARAM as a notice code and LPARAM as the information related with the notice code. The notice codes are defined in OthelloWindowWTL.h. The notice code is as follows:

Table of User-defined Message NM_OTHELLO (= UM_OTHELLO)

WPARAM (notice code)

LPARAM

Description

ON_MYSTONE

If an opponent puts its stone at the coordinates of (x, y), the (x, y) is (LOWORD(lParam), HIWORD(lParam))

When an opponent put its stone, OthelloWindowWTL sends the message NM_OTHELLO (= UM_OTHELLO) with the notice code ON_MYSTONE to its parent window.

ON_YOURSTONE

If a user puts his/her stone at the coordinates of (x, y), the (x, y) is (LOWORD(lParam), HIWORD(lParam))

When a user put his/her stone, OthelloWindowWTL sends the message NM_OTHELLO (= UM_OTHELLO) with the notice code ON_YOURSTONE to its parent window.

ON_PASS

If an opponent passes its turn, lParam is PLAYER1. If a user passes his/her turn, lParam is PLAYER2.

If a user or an opponent passes his/her/its turn since he/she/it does not have any place where he/she/it can put his/her/its stone, OthelloWindowWTL sends the message NM_OTHELLO (= UM_OTHELLO) with the notice code ON_PASS to its parent window.

ON_FINISH

An opponent's score is LOWORD(lParam) and a user's score is HIWORD(lParam). But, if OthelloWindowWTL has sent NM_OTHELLO (= UM_OTHELLO) with the notice code ON_NOPLACE previously, lparam of NM_OTHELLO (= UM_OTHELLO) will be zero.

When the game is over, OthelloWindowWTL sends the message NM_OTHELLO (= UM_OTHELLO) with the notice code ON_FINISH to its parent window.

ON_NOPLACE

An opponent's score is LOWORD(lParam) and a user's score is HIWORD(lParam).

Both players have no place to put his/her/its stone, OthelloWindowWTL sends the message NM_OTHELLO (= UM_OTHELLO) with the notice code ON_NOPLACE to its parent window. And then, OthelloWindowWTL automatically sends NM_OTHELLO (= UM_OTHELLO) with the notice code ON_FINISH next, where lparam is zero.

ON_START

Not determined yet

Reserved for the future

ON_STOP

Not determined yet

Reserved for the future

ON_LEVEL

Not determined yet

Reserved for the future

The Classes OthelloCore, OthelloCore0, OthelloCore1, OthelloCore2, and OthelloCore3

I would not explain all the member functions. Instead, I would explain the strategies of the artificial intelligence of Nura Othello. I think that it would be much more helpful for you to understand the algorithms of the artificial intelligence of Nura Othello. The core of cores of the artificial intelligence of Nura Othello is the function virtual bool SeekBestPoint (int* px, int* py, const int player = PLAYER1). Most of the others are the implementations of the Nura Othello rules. How to find where the computer shall put its stone, is virtually everything of the OthelloCore-series class. So, the strategy is implemented in this function SeekBestPoint (...).

Inheritance Structure

  • OthelloCore0 is derived from OthelloCore, and has an artificial intelligence of level 0.
  • OthelloCore1 is derived from OthelloCore, and has an artificial intelligence of level 1.
  • OthelloCore2 is derived from OthelloCore1, and has an artificial intelligence of level 2.
  • OthelloCore3 is derived from OthelloCore2, and has an artificial intelligence of level 3.

The strategies of artificial intelligence

The strategy of OthelloCore

It provides the basic functions for artificial intelligence. It is almost a generic class so that all the OthelloCore-series classes are derived from it directly or indirectly. Actually, it does not have any artificial intelligence factors since the function SeekBestPoint (...) is a pure virtual function as follows.

virtual bool SeekBestPoint (int* px, int* py, const int player = PLAYER1) = 0;

In the future, I would develop a network version as well. In that version, SeekBestPoint (...) will receive the input from another user on the network. That is why I made it a virtual function.

The strategy of OthelloCore0

It has level 0 of artificial intelligence. It was made for a beginner to learn the rules of Nura Othello. The computer puts its stones any place where it can put its stones without thinking anything. It is brainless mode. So, it does not have any strategy.

The strategy of OthelloCore1

It has level 1 of artificial intelligence. It chooses the place where the computer can get the most number of stones if it puts its stone. Among the candidate places where the computer can put its stone, it chooses the most greedy place. Normally, a human beginner chooses this strategy.

The strategy of OthelloCore2

It has level 2 of artificial intelligence. The computer shall try to obtain more advantageous positions first. The priority of the place is as follows. P1 is the most advantageous and P9 is the most disadvantageous. Among the candidate places where the computer can put its stone, it chooses the most advantageous place.

Othello Board with Priority marks

P1

P3

P2

P2

P2

P2

P3

P1

P3

P9

P7

P8

P8

P7

P9

P3

P2

P7

P4

P5

P5

P4

P7

P2

P2

P8

P5

P6

P6

P5

P8

P2

P2

P8

P5

P6

P6

P5

P8

P2

P2

P7

P4

P5

P5

P4

P7

P2

P3

P9

P7

P8

P8

P7

P9

P3

P1

P3

P2

P2

P2

P2

P3

P1

It is a more smarter strategy than that of level 1, especially in the long-distance viewpoint. Usually, a human of intermediate level chooses this strategy. However, the priority of each place is changed according to situations. So, the computer needs to change the priority of each place according to the situation, but it uses a fixed priority table. It is not flexible, and does not reflect the situation to its decision making.

The strategy of OthelloCore3

I improves the weaknesses of level 2. It is level 3. It changes the priority of each place according to situations, and reflects its changed situation to its decision making. It simulates a line Othello which has only one line, so that it can predict several steps and choose the best result. However, it also has a weakness. It uses only a line Othello which is one-dimensional. So, it is vulnerable to two-dimensional attacks of its opponent. If you do not understand this explanation very well, you can understand it when you look into the source.

However, at the end and final stages of the game, the strategy of levels 1 and 2 are far better than others, respectively. So, it changes its strategies according to the stage of the game.

Points of Interest

As I mentioned above, I could not solve one problem which is the withdrawal problem. I simply disabled the withdrawal function since it works very well on my computer but it works terribly on some other computers. I doubt some thread problem, but, at the moment, I do not know the reason exactly. If you want to enable the withdrawal function and check whether it works or not, comment the statements of line 55 in stdafx.h in the folder OthelloWTL, as follows:

// #define NOTWITHDRAWAL

VC++ 8.0X uses ATL 3.0, while VC++ 7.1 uses ATL 7.1. Although both use the same WTL 8.0, the source for VC++ 7.1 is not compatible with VC++ 8.0X. So, in order to make it able to be compiled with VC++ 8.0X, though it was developed with VC++ 7.1 (ATL 7.1), I made ATLVersion.h and included it in stdafx.h. ATLVersion.h is the same file as that of Nura Tetris. In this project, ATLVersion.h works very well, but I do not think that it works for all the projects written for VC++ 7.1 to be able to be compiled with VC++ 8.0X very well. If there is anyone who is interested in downward compatibility of ATL, I want to encourage him or her to improve ATLVersion.h.

Othello Customizer

Image 14

I would not explain the source code of this OthelloCustomizer. Instead, I would introduce how to use this utility program. If you run this program and translate all the messages into your language in the corresponding edit windows and save it, you can get a NuraOthello.ini. If you put it in the same folder in which NuraOthello.exe exists, NuraOthello.exe will use NuraOthello.ini to make all messages in your language. Also, you can save as a different name such as NuraOthelloRussian.ini. It would not work as itself for NuraOthello.exe but you can keep it as a specific language pack for NuraOthello.

Acknowledgement

I want to thank Michael Dunn for his excellent articles on WTL for MFC programmers. I learned a lot about WTL from his article. His articles can be found here. I want to also thank Sergey Solozhentsev for his great work on the WTL Helper and the WTL Wizards. You can get his WTL Helper here and here, and its manual here and here. Do not be confused. His WTL Wizards are different from the normal WTL App Wizard which can be installed with setup71.js, for instance. His WTL Wizards support a split window framework as well. You can also get his WTL Wizards here and its manual here. It provides me with a lot of convenience when I code using WTL. Most of all, I really appreciate God and my wife Nura. He gave me her, and she is always on my side and is my firm supporter.

History

29 Dec 06 - NuraOthello 1.6 and Othello Customizer 1.0 Released.
13 Jan 07 - Source code updated a bit.
20 Jan 07 - Article and source code updated a bit.
1 Feb 07 - NuraOthello 1.7 and Othello Customizer 1.1 released; Its rule changed according to international Othello rule and a bug related with time limitation option fixed up.

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

 
QuestionCompiling with Visual Studio 2008 Pin
Dr Bob.25-Feb-10 11:08
Dr Bob.25-Feb-10 11:08 
GeneralI changed the rule of Nura Othello! Pin
PARK Youngho2-Feb-07 11:42
PARK Youngho2-Feb-07 11:42 
QuestionWhere's the beef? Pin
NGS 54967212-Jan-07 5:34
NGS 54967212-Jan-07 5:34 
AnswerThank you for your suggestions! Pin
PARK Youngho12-Jan-07 9:17
PARK Youngho12-Jan-07 9:17 
GeneralNice Bio Pin
NormDroid12-Jan-07 4:31
professionalNormDroid12-Jan-07 4:31 
GeneralRe: Nice Bio Pin
Chris Maunder21-Jan-07 21:11
cofounderChris Maunder21-Jan-07 21:11 
QuestionDoes size matter? Pin
NGS 5496722-Jan-07 5:34
NGS 5496722-Jan-07 5:34 
AnswerWould you please specify your question more in detail? Pin
PARK Youngho2-Jan-07 23:30
PARK Youngho2-Jan-07 23:30 
GeneralRe: Would you please specify your question more in detail? Pin
NGS 5496723-Jan-07 4:10
NGS 5496723-Jan-07 4:10 
GeneralRe: Would you please specify your question more in detail? Pin
Ilíon2-Feb-07 8:08
Ilíon2-Feb-07 8:08 
GeneralAh~! I didn't know the meaning of the word "stones". Pin
PARK Youngho2-Feb-07 11:18
PARK Youngho2-Feb-07 11:18 
GeneralRe: Ah~! I didn't know the meaning of the word "stones". Pin
Ilíon2-Feb-07 11:51
Ilíon2-Feb-07 11:51 
GeneralYield Pin
Frank_Cheng29-Dec-06 17:51
Frank_Cheng29-Dec-06 17:51 
GeneralPlease see the rule of Nura Othello! Pin
PARK Youngho29-Dec-06 23:51
PARK Youngho29-Dec-06 23:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.