CEBoard’s Engine Interface

Because of a few limitations of Windows CE, it was not really possible to incorporate engines in CEBoard as it is done on desktops with Winboard and UCI protocols. It order to have a decent control of the engine, I chose to put engines in DLL and use COM like interfaces for communications between CEBoard and the engines : the Engine and CEBoard will run on different threads in the same running process.

 

Anyway, in order to simplify the model further, it is not a real COM relationship between CEBoard and engines :

·         CEBoard gets the interface implemented by the engine through a function exported by the engine DLL, there is no registry stuff involved (nor class factories),

·         CEBoard passes its own interface to the same function, the engine can then store the pointer and reuse it late.

·         The interfaces do not inherit from IUnknown an there is no reference counting.

 

Here is the DLL exported function:

 

interface IEngine;

typedef IEngine *LPENGINE;

 

interface ICEBoard20;

 

typedef LPENGINE (*LoadEngineProc)(ICEBoard20 *pCEBoard);

 

#define EngineProcName L"LoadEngine"

 

What does that mean ?

The DLL must export a function named “LoadEngine”, which takes a pointer to an ICEBoard20 interface (described later) and returns a pointer to a IEngine interface.

 

How and when CEBoard loads a DLL and calls this function ?

At initialization, CEBoard looks in its Engines folder and enumerate all its subfolders ; in each of these subfolders, CEBoards checks if a DLL with the same name than the subfolder exists; is so, it considers it as en engine.

When the user starts an engine, CEBoard loads the corresponding DLL, tries to locate the LoadEngine function and calls it, passing it a pointer to an interface implemented by an internal CEBoard’s object, the Engine Driver. LoadEngine creates the engine thread, stores the pointer passed by CEBoard and returns an pointer to its implementation of the IEngine interface.

 

Note : in almost all interface functions, the strings are passed as Unicode as it is the standard of Windows CE.

 

IEngine interface

Now it is time to have a closer look at the interface that the engine must implement as well as the interface implemented by CEBoard.

 

#define ENGINE_INTERFACE_VERSION  2

 

#define MOVES_UCI                        1

 

typedef struct tagEngineProperties {

      DWORD dwSize;     // Structure size

DWORD dwVersion;  // Version of the interface

      DWORD dwCaps;

      TCHAR sEngineName[32];

} EngineProperties;

 

 

 

interface IEngine {

  BOOL GetProperties(EngineProperties *pProps) = 0;

  virtual void StartGame(BOOL bPlayBlack, BOOL bAnalyze, LPCTSTR sFen) = 0;

  virtual void EndGame() = 0;

  virtual void Release() = 0;

  virtual void SendMove(LPCTSTR sMove) = 0;

  virtual BOOL ShowOptions(HWND hWnd) = 0;

  virtual HMENU GetMenu() = 0;

  virtual BOOL HandleCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) = 0;

  virtual void SetPosition(LPCTSTR sFEN) = 0;

  virtual void MoveNow() = 0;

  virtual BOOL IsAlive() = 0;

  virtual void GetMessages(BOOL bWantMessages) = 0;

};

 

GetProperties

Called by CEBoard immediately after LoadEngine. CEBoard’s fills the dwSize field of the structure, whiwh allows the engine to know which fields to fill.

sEngineName = returns the name of the Engine.

MOVES_UCI = put this value if the engines uses UCI’s move format (ie coordinates, like e2e4 or e7e8Q), clear this value if the engine uses algebraic notation (e4, e8=Q)

 

StartGame

Called by CEBoard when the user starts a new game or a new position.

 

EndGame

Called by CEBoard when the user closes the game window.

 

Release

Called by CEBoard when the user closes CEBoard.

 

SendMove

Called by CEBoard when the user has entered a move. The notation is either coordinates (UCI mode) or algebraic.

 

ShowOptions

Called by CEBoard to allow the user to change options (for example level of play) of the engine.

 

GetMenu

Called by CEBoard to get an handle to a popup menu to display when the user clicks on the Engine button. It allow the engine to offer its own commands.

 

HandleCommand

Called by CEBoard when the user has selected an option in the engine’s provided menu. Allow the engine to handle the commands it offers.

 

SetPosition

Called by CEBoard when the user has jumped to a past position in the game.

 

MoveNow

Force the engine to move : if it was the engine’s turn to play, it must stop thinking and play immediately. If it was the player’s turn, the engine has to switch colors and start thinking.

 

IsAlive

Called periodically by CEBoard to check it the engine is still running. Implementation: for example, simply check that the engine’s thread is still running.

 

GetMessages

Called by CEBoard to indicate that the user wants to display engine’s feedback such as the best move so far, the evaluation score, …

 

ICEBoard20 interface

A pointer to a ICEBoard20 interface is passed to the engine via the LoadEngine function. This interface allows the engine to interact with CEBoard. Here is the definition of the interface :

 

interface ICEBoard20 {

      // Méthodes de la version 1

      virtual void EngineMove(LPCTSTR sMove) = 0;

      virtual void FatalError(LPCTSTR sError) = 0;

      virtual void GameFinished(LPCTSTR sResult, LPCTSTR sComment) = 0;

      virtual void WhoPlays(LPCTSTR sPlayer) = 0;

      virtual void SwitchSides() = 0;

      virtual void ShowThinking(BOOL bShow) = 0;

      virtual void SetTimeControl(int nSecByMove, int nMoves1, int nSec1,
                                  int nMoves2, int nSec2, int nSec3,
                                  int nInc) = 0;

      virtual void EngineFeedback(int depth, int nodesSec, int totalNodes,
                                  int nTime, LPCSTR sEval,
                                  LPCSTR sVariante) = 0;

      virtual void GetTimeInfo(int *pwtime, int *pbtime, int *pmovestogo) = 0;

};

 

EngineMove

Called by the engine to play a move. Move format is PGN like.

 

FatalError

Called by the engine when an unrecoverable error is encountered.

 

GameFinished

Called by the engine when it detects that the game is finished :

·         sResult = PGN like format, i.e. “1-0”, “0-1”, “1/2-1/2” or “½-½”

·         sComment = detailed explanation, for example “Threefold repetition”

 

WhoPlays

Called by the engine to indicate the name to store in PGN file. Used for example by Crafty SE to indicate which personality has been selected.

 

SwitchSides

Called by the engine to tell CEBoard that the engine now plays the other color.

 

ShowThinking

Called by the engine to tell CEBoard to display the EngineFeedback, or to hide it.

 

SetTimeControl

Called by the engine to tell CEBoard the user’s selected time control.

 

EngineFeedback

Called by the engine to indicate the current state of its thinking. Beware : the strings here are in ANSI instead than Unicode !

 

GetTimeInfo

Called by the engine to get the time available until next time control (to be used when not in fixed time mode)