Contents
- Introduction
- The name of Nura Othello
- The rules of Nura Othello
- The features of Nura Othello
- The usage of Nura Othello
- Background
- The source code
- Environment
- Using the code
- Entire Structure
- The Class CMainDlg
- The Class OthelloWindowWTL
- The user-defined Message NM_OTHELLO (= UM_OTHELLO) of OthelloWindowWTL
- The Classes OthelloCore, OthelloCore0, OthelloCore1, OthelloCore2, and OthelloCore3
- Inheritance Structure
- The strategies of artificial intelligence
- The strategy of OthelloCore
- The strategy of OthelloCore0
- The strategy of OthelloCore1
- The strategy of OthelloCore2
- The strategy of OthelloCore3
- Points of Interest
- Othello Customizer
- Acknowledgement
Introduction
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.
- Nura Othello is played on a 8 X 8 board. It looks like a chess board.
- Players shall put their stones on a square cell, not on a line or on a cross point of the lines.
- The game begins with putting two stones for each player in the center of the board.
- 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).
- Players can put their stones only on the place where they can surround their opponent's stone(s);
- Players shall put their stones alternatively.
- 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.
- Eventually, the player who has more stones will win the game.
- 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.
- 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.
- According to the IQ of the artificial intelligence required from the game, a user can choose from level 0 to level 3.
- At the start of the game, the initial positions of the four stones will be determined randomly. It has six possibilities, as follows:
- It shows who is winning at the moment, by a graph.
- It has the option to let the computer put his stone first or second.
- 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.
- 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.
- To start the game, click the button "Start".
- During the game, if you want to cancel the game, click the button "Cancel".
- Before the game starts, if you want your computer to put a stone first, check the button "Com. First".
- Before the game starts, if you want to enjoy the stress of time limitation, check the button "Time Limit".
- 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.
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.
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
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
.
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:
#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:
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);
- It is a constructor.
- 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
.
- 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
.
- Language will be automatically chosen according to the default language of Windows.
OthelloWindowWTL (UINT message, int lang, bool bAutoFinish);
- It is another constructor.
- The first and third parameters are the same as described above.
- 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);
- It makes the Othello game start.
- The return value is
true
when the game starts, and is false
when it fails.
inline bool Stop (void);
- 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.
- 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);
- It initializes the Othello game.
- 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 |
|
|
|
diag |
0 or 6 |
1 or 7 |
2 |
Figure |
|
|
|
diag |
3 |
4 |
5 |
- 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
.
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);
- 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.
- The return value is
true
when it succeeds, and false
when it fails.
int WhoWin (int* pPlayer1 = 0, int* pPlayer2 = 0) const;
- It tells who is winning or has won.
- 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.
- 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.
- 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;
- It tells whose turn it is next.
- 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 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
|
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 (...)
.
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.
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.
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.
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.
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.
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.
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:
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.
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.
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.