Skip to content

01 Program Structure

Frank Kopp edited this page Dec 13, 2017 · 7 revisions

Chessly - Structure

Background

I have designed Chessly in a very specific way. I did not just want a chess engine with a ui but also something very extensible so that I can add additional functionality later. I also wanted to apply Java patterns to learn about them and other best practices.

Main classes

Chessly

The Chessly class is used to start up the application using a Playroom and a UI (user interface). It also processes command line arguments. It gives access to the ChesslyProperties which has configuration information about the application. The Chessly main logging class ChasslyLogger can also be accessed through this class.

When the Chessly class is instantiated as a Singleton in the main() it creates a UI through UserInterfaceFactory. The UI needs to implement the UserInterface interface which is basically an Observer. This way the ui is easily changed - e.g. simple console ui, Swing UI or the current JavaFX UI.

It then creates/gets the Playroom (also Singleton) and adds the UI as an observer to the Playroom.

It then checks if the configuration wants to autostart playing and starts the playroom accordingly. If not the UI needs to start the actual playing (or other things).

Playroom

The Playroom class is the main controlling part of the model/application. It represents and gives access to the model independently from the user interface (Model View Controller). The Playroom is started automatically from the Chessly class startup or through the user interface (UI). It can be configured through properties and/or the user interface. It is responsible to build and start a game with players and also to give access to all model information which has to be queried and changed by the user interface. The Playroom is running in a separate thread to actually play one or more games in a row. For doing this it creates a game with the current settings and also creates two players to play in that game. When players and game are initialized it starts the game which is also running in a separate thread.

UI

The UI in Chessly can be very simple to very sophisticated. As the Playroom can be fully started and configured through configuration a ui is basically optional. Obviously for a chess game which should be playable by human players the ui needs to be able to display what the game status is and also needs to accept human player commands such as "start new game" or "make move xyz".

Basically the model (Playroom, Game, Player, ...) should never rely on a ui being present or doing something important. E.g. there is no way to directly "print" anything to the ui. On the other hand the UI should never expect the model to notify about all model changes. This would be impractical so that only major status changes will be communicated through the observer pattern. For some ui parts it will be necessary to employ a loop to query the model and update the ui. E.g. the ObservableEngine Interface allows access to engine internal data and stats which are best queried regularly by the ui (e.g. every 50ms).

The UI can only talk to the Playroom as a controller for the model.

The new JavaFX UI uses a FXML based ui design (created with Scene Builder 2.0) with several additional windows/dialogs either also via FXML or created in the code itself.

The JavaFX UI observes the Playroom and if playing the Game and Players and also the Engine (through the ObservableEngine interface) if one player is a engine player.

As common in JavaFX (and Swing for that matter) the UI runs in a separat thread. Therefore careful exchange of information through the observer pattern is important.

Game

The Game class will be instantiated by the Playroom whenever a game should be played. The Game class needs two players, two time values and a flag to indicate that this game should be time based. Therefore before creating a game two Players need to be created.

The Game handles all playing according to the full chess rules and also controls timers for the players. It has a chess board for the current position and to commit the players' move to.

The Game class also uses its own thread to do the actual playing. This way it can do stuff independent from the actual players. It must be started (startGame) after creation.

The Game object is mainly managed by a state engine (StatusController) and can be in these states: INITIALIZED | RUNNING | PAUSED | STOPPED | OVER | FINISHED

A game can be in state OVER exactly if:

  • There are no more moves at all OR
  • Time is up for at least one player OR
  • One User has resigned the game

When a game is OVER there must be a WINNER or it is a DRAW.

It knows which player has to do a move and asks that player for a move. If the player returns a move it is checked if it is a legal move and then commits the move to the board, It then notifies the observers (mainly ui) and asks the next player for a move.

The class also checks if a game is over because there are no more moves, repetition, 50 moves rule our because a player ran out of time.

A game can be paused and resumed which stops the timers for the players. This is usually triggered by the UI through the Playroom.

Game uses a GameBoard to store the position and also to generate all legal moves. A GameBoard is in fact the part of the Game class that understands chess rules and how to generate legal moves.

GameBoard

The GameBoard is a Java interface for representing a chess board. The GameBoard holds all information needed to fully reflect a chess game position.

See the GameBoard Interface for details.

The GameBoardImpl class is the implementation of the GameBoard interface the Game class and the UI uses. It is expected that Engines will translate this into their own board representation for their calculations as this implementation is not aimed for speed or efficiency.

Player

A Player is defined using the interface Player to be used together with the GAME class.

  • A player has a NAME, a certain COLOR.
  • A player can have one of the following states: WAITING | THINKING | HAS_MOVE | STOPPED

Typically a player will be either a human, a computer.

A player also runs in a separat thread. For convenience am Abstract Player implementation is provided which takes care of controlling its own thread and exchange of information with other components - mainly the Game.

Human Player

The HumanPlayer class extends the Player class and implements the abstract methods. Instead of calculating a move the HumanPlayer signals the UI (through notify observer) that it wants a move from the human player. The UI will receive this move from the human player and sends it back to the HumanPlayer object.

In addition a human player can request an UndoMove via the UI and the Playroom which will be handled by the Game via a flag in the HumanPlayer. (The HumanPlayer will send back a null instead of a valid move which triggers the Game to check for the wantsUndoMove flag.)

Computer Player

A ComputerPlayer uses an Engine to calculate the next move.

Engine

Engines for Chessly can be implemented using the Engine Interface.

Engines run in the same thread as the player as the Engine is called via the player directly. GameMove getNextMove(GameBoard board);

So the most simple Engine uses the provided board and generates all legal moves and picks one from the list (Example implementations are Adam (picks the first move in the list) and Random (picks a random move from the list).

Adam: public GameMove getNextMove(GameBoard board) { return board.generateMoves().get(0); }

For more details on engines please see "02 Engines"

Architecture Illustration

Clone this wiki locally