The grand design

Discussion of chess software programming and technical issues.

Moderator: Ras

SuneF
Posts: 127
Joined: Thu Sep 17, 2009 11:19 am

The grand design

Post by SuneF »

I wonder how many have considered the design of their engine from an object orientated perspective.

In particular:
1: What classes do you use and what is their resposibility?
2: How are they coupled?
3: What patterns are you using?
4: When do you trade design for speed?

I'm kinda struggling a bit myself to find the right balance and design.

I've designed a ChessGame class to encapsulate the state of the game.
There is an abstract Protocol class, which the ChessGame knows about.
The Protocol is specialized into WinboardProtocol and UciProtocol classes - of which the ChessGame doesn't know about.
The idea here is to isolate all protocol stuff from the main system, making it easier to implement new protocols without changing so much as a line in the very messy game/search stuff.

Okay that is basic I guess.
Then I currently have Board, Node and Tree classes.
The board is for holding the current state.
Node is like an extended Board class, it contains Undo information, move lists and so on.
The Tree is a Node container for holding the entire search info.

The main problem here is that these classes get fat, real fat real quick.
Can they be broken up in a natural way?

Another design issue, is which class should be resposible for driving the search()?
The search must call the Evaluation(), it must do pruning and extensions, so this would make Board a candidate.
But how can the Board know about "the next ply", the Tree knows about the plies, so this would make Tree a candidate.
Finally, at every node we have lots of parameters, alpha, beta, depth etc.. These are natually stored in a Node or locally declared.
This would make Node a candidate.
My favorite is the Node class, primarily for notation reasons, though the nodes would have to be linked or know about the Tree to go to the next node.

One design decision I've made, is that I accept "global" tables, ie. data floating in a namespace.
My reasoning is, that the notation would get awkward if everything had to get prefixed by some named object or as static members of a class. Not to mention it would probably be slower.

There are many more issues of course, not to mention what is a good parallel design?
Dann Corbit
Posts: 12791
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: The grand design

Post by Dann Corbit »

SuneF wrote:I wonder how many have considered the design of their engine from an object orientated perspective.

In particular:
1: What classes do you use and what is their resposibility?
2: How are they coupled?
3: What patterns are you using?
4: When do you trade design for speed?

I'm kinda struggling a bit myself to find the right balance and design.

I've designed a ChessGame class to encapsulate the state of the game.
There is an abstract Protocol class, which the ChessGame knows about.
The Protocol is specialized into WinboardProtocol and UciProtocol classes - of which the ChessGame doesn't know about.
The idea here is to isolate all protocol stuff from the main system, making it easier to implement new protocols without changing so much as a line in the very messy game/search stuff.

Okay that is basic I guess.
Then I currently have Board, Node and Tree classes.
The board is for holding the current state.
Node is like an extended Board class, it contains Undo information, move lists and so on.
The Tree is a Node container for holding the entire search info.

The main problem here is that these classes get fat, real fat real quick.
Can they be broken up in a natural way?

Another design issue, is which class should be resposible for driving the search()?
It seems to me that search is a property of the game state. It isn't really owned by board or nodes or any of the others that I can think of.

So I would probably make it Game.Search()
The search must call the Evaluation(), it must do pruning and extensions, so this would make Board a candidate.
But how can the Board know about "the next ply", the Tree knows about the plies, so this would make Tree a candidate.
Finally, at every node we have lots of parameters, alpha, beta, depth etc.. These are natually stored in a Node or locally declared.
This would make Node a candidate.
My favorite is the Node class, primarily for notation reasons, though the nodes would have to be linked or know about the Tree to go to the next node.

One design decision I've made, is that I accept "global" tables, ie. data floating in a namespace.
My reasoning is, that the notation would get awkward if everything had to get prefixed by some named object or as static members of a class. Not to mention it would probably be slower.

There are many more issues of course, not to mention what is a good parallel design?
I always ask these questions about class X:
If x IS A y, then it is a specialization of y (inheritance).
If x HAS a y, then y is a member object.
If x PERFORMS y, then y is a member function of x.
It helps me to think along these lines because (for me) it creates the most natural representation.
SuneF
Posts: 127
Joined: Thu Sep 17, 2009 11:19 am

Re: The grand design

Post by SuneF »

Dann Corbit wrote: It seems to me that search is a property of the game state. It isn't really owned by board or nodes or any of the others that I can think of.

So I would probably make it Game.Search()
I think yes, Game would expose a public method called Search(), it would be needed by the Protocol when interfacing the Game. Game would thus take the role of a controller for managing the search and state stuff.
But how would Game implement Search(). Game would have references to at least a Board and a Tree. So the request would delegate to Tree which would delegate to the current node which would then do the search().

Hmm or what?
Dann Corbit wrote: I always ask these questions about class X:
If x IS A y, then it is a specialization of y (inheritance).
If x HAS a y, then y is a member object.
If x PERFORMS y, then y is a member function of x.
It helps me to think along these lines because (for me) it creates the most natural representation.
Yes indeed, no argument there :-)

I see the confusion now, because Game performs Search you want Game to implement the Search()? There is problem with that though, Game is not the information expert, Board and Node is. So to keep the amount of couplings low, Board and Node are the two best candidates (IMHO).
Dann Corbit
Posts: 12791
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: The grand design

Post by Dann Corbit »

SuneF wrote:
Dann Corbit wrote: It seems to me that search is a property of the game state. It isn't really owned by board or nodes or any of the others that I can think of.

So I would probably make it Game.Search()
I think yes, Game would expose a public method called Search(), it would be needed by the Protocol when interfacing the Game. Game would thus take the role of a controller for managing the search and state stuff.
But how would Game implement Search(). Game would have references to at least a Board and a Tree. So the request would delegate to Tree which would delegate to the current node which would then do the search().

Hmm or what?
Dann Corbit wrote: I always ask these questions about class X:
If x IS A y, then it is a specialization of y (inheritance).
If x HAS a y, then y is a member object.
If x PERFORMS y, then y is a member function of x.
It helps me to think along these lines because (for me) it creates the most natural representation.
Yes indeed, no argument there :-)

I see the confusion now, because Game performs Search you want Game to implement the Search()? There is problem with that though, Game is not the information expert, Board and Node is. So to keep the amount of couplings low, Board and Node are the two best candidates (IMHO).
Board.search() can make sense to me, but node.search() sounds very strange to me. It feels like an atom searching his universe.
Perhaps tree.search()?
Aleks Peshkov
Posts: 916
Joined: Sun Nov 19, 2006 9:16 pm
Location: Russia
Full name: Aleks Peshkov

Re: The grand design

Post by Aleks Peshkov »

My Node object knows internally how to generate a move list, but do not know what to do with it. I store Evaluator object inside Node object. Node evaluates itself using static evaluator or various recursive search evaluators (pv_search, q_search, etc.).

Node can copy own evaluator with different parameters or can create a different evaluator when it needed to evaluate recursively its child nodes.

Code: Select all

class Node {
    //color and tree independent position information
    PieceLayout my; //side to move pieces
    PieceLayout op;

    class Search {
         typedef bool (*Evaluator) (Node&);
         Evaluator evaluator;
         Ply depth;
         Eval alpha, beta;
     } evaluator;
};
User avatar
OliverUwira
Posts: 170
Joined: Mon Sep 13, 2010 9:57 am
Location: Frankfurt am Main

Re: The grand design

Post by OliverUwira »

If you want to break up your big classes, you could split them according to the Model-View-Controller Architecture.

E.g for the Board class:

Board view => graphics and mouse handling
Board model => keep board state and updates (setMove, unsetMove, setPosition, throw Exception for illegal moves)
Board controller => interaction with other classes, send events and the like.

Actually I would prefer to have a more global controller, e.g. a GameState object that acts as a dispatcher. E.g. you want a move not only played at the board, but also update the score sheet etc... so the GameState would notify all concerned objects that a move has been played.

I would make the search neither part of the Board nor the Tree class but I would rather make an Engine class. I'm thinking of a design like this:

Code: Select all

                      Player (abstract)
                     /          |            \
                    /           |             \
               Human     ICS        Engine
                                           /        \
                                          /          \
                                        UCI     XBoard
Think of the controller notifying a Player that it is his turn to move. The Player will raise an event if he wants to play a move. Now, if you notified a Human, the controller just waits for move input after starting the humans clock. For an ICS connection, you wait for the connection to raise the move event once it has received the remote players move. In case of an Engine, you call engine.search() and wait. The protocol handler for UCI and Winboard should somehow be part of the Engine.

Conceptually I have something like the following in mind.

Code: Select all

public abstract class Engine extends Player
{
      public abstract void startEngine();
      public abstract void startSearch();
      public abstract void abortSearch();

      public abstract void firePrincipalVariationEvent(Move[] pv);
      public abstract void fireBestMoveEvent(Move best, Move ponder);

      ....
}

public class UciEngine extends Engine
{
       protected String exePath;
       protected Stream pipe;  // no idea how to do the piping in Java yet (-:

       public void startEngine()
       {
             // start engine process, create pipes...
       }

       public void startSearch()
       {
            // pack the following into a separate thread an return,
            // so that caller won't wait for this method to return.

             pipe.printf("go wtime 200000 ....");
             
             // read input from pipe
             // and parse it
             
             this.fireBestMoveEvent(best, ponder);
       }
}
uaf
Posts: 98
Joined: Sat Jul 31, 2010 8:48 pm
Full name: Ubaldo Andrea Farina

Re: The grand design

Post by uaf »

back to work on Frenzee, Sune? :)
SuneF
Posts: 127
Joined: Thu Sep 17, 2009 11:19 am

Re: The grand design

Post by SuneF »

Dann Corbit wrote: Board.search() can make sense to me, but node.search() sounds very strange to me. It feels like an atom searching his universe.
Perhaps tree.search()?
Board.Search() is possible, but I think the Board already has its hands full with Evaluation and making smart decisions about the current state of the Board.
Tree.Search() at first looks like the most natural choice to me. Downside is one would have to pass around another node-parameter and there would be no implict this pointer, so one would have to use the C-style notation (node->x,.. node->y).

An atom searching the Universe is perhaps strange, but what if the atoms are all linked. The nodes could be the media through which the information flows, ie. like sound waves propagate through air molecules..
Binary search trees and such work much the same way.
Guess it would result in something like this:

score = - next->Search(board, alpha, beta...);
SuneF
Posts: 127
Joined: Thu Sep 17, 2009 11:19 am

Re: The grand design

Post by SuneF »

OliverUwira wrote:If you want to break up your big classes, you could split them according to the Model-View-Controller Architecture.

E.g for the Board class:

Board view => graphics and mouse handling
Board model => keep board state and updates (setMove, unsetMove, setPosition, throw Exception for illegal moves)
Board controller => interaction with other classes, send events and the like.
Yes MVC is not far off, of course there would be no actual view since the engine is using standard I/O to communicates, it's more of a service layer I suppose.
Actually I would prefer to have a more global controller, e.g. a GameState object that acts as a dispatcher. E.g. you want a move not only played at the board, but also update the score sheet etc... so the GameState would notify all concerned objects that a move has been played.

I would make the search neither part of the Board nor the Tree class but I would rather make an Engine class. I'm thinking of a design like this:

Code: Select all

                      Player (abstract)
                     /          |            \
                    /           |             \
               Human     ICS        Engine
                                           /        \
                                          /          \
                                        UCI     XBoard

Think of the controller notifying a Player that it is his turn to move. The Player will raise an event if he wants to play a move. Now, if you notified a Human, the controller just waits for move input after starting the humans clock. For an ICS connection, you wait for the connection to raise the move event once it has received the remote players move. In case of an Engine, you call engine.search() and wait. The protocol handler for UCI and Winboard should somehow be part of the Engine.

Conceptually I have something like the following in mind.

Code: Select all

public abstract class Engine extends Player
{
      public abstract void startEngine();
      public abstract void startSearch();
      public abstract void abortSearch();

      public abstract void firePrincipalVariationEvent(Move[] pv);
      public abstract void fireBestMoveEvent(Move best, Move ponder);

      ....
}

public class UciEngine extends Engine
{
       protected String exePath;
       protected Stream pipe;  // no idea how to do the piping in Java yet (-:

       public void startEngine()
       {
             // start engine process, create pipes...
       }

       public void startSearch()
       {
            // pack the following into a separate thread an return,
            // so that caller won't wait for this method to return.

             pipe.printf("go wtime 200000 ....");
             
             // read input from pipe
             // and parse it
             
             this.fireBestMoveEvent(best, ponder);
       }
}

Yes for a View that sounds like a good design.
SuneF
Posts: 127
Joined: Thu Sep 17, 2009 11:19 am

Re: The grand design

Post by SuneF »

uaf wrote:back to work on Frenzee, Sune? :)
A little bit now and then... :)