Bringing all the modules together is the graphical user interface which allows the player to check the state of the game as well as configure certain aspects of it. This interface was made using PySimpleGUI which is a python library that allows to easily create custom Graphical User Interfaces.
Before starting the game, the user has to input the dimensions of the chessboard and pieces, this is done by selecting the “Configuration > Dimensions” tab and filling in the corresponding fields. After this, the user can start the configuration steps by pressing the “New Game” button which are explained later.
In order to understand how the program works and how all modules are integrated, it is important to know that the interface is based on two main state machines, one for the game’s global structure and another for the initial configuration steps. For real-time user interaction it is necessary to run the interface in the main thread (it’s a requirement for the PySimpleGUI library) and launch other large processes like the chess engine in different threads.
The next diagram briefly shows the main state machine where the blue lines represent the game flow and the red ones the ending game process:
The stby (stand by) is an idle state whose main function is to wait, for example, while a task is being executed in another thread, the interface keeps running and updating in the main thread.
The playerTurn is in charge of analyzing the human player's move. It waits for the user to press the “Clock” button which indicates that the move has been made. Then, the vision module compares the previous state of the board with the current one and generates a list of the squares that have changed the most, this list is passed to the chess logic module to identify the most probable move and its validity.
Once a valid move has been made, it generates a sequence of moves with the "sequenceGenerator" function. This is then passed to the "updateBoard" function along with the current state of the board (as reference) in order to update the interface; this process also takes place in the robot's turn.
The pcTurn is executed in a different thread that uses Stockfish, through the Python-Chess library, to generate the best move based on the current state of the board. After finding the move it changes to the robotMove state in which the robot move is executed in a different thread.
The state of the board is saved in a "chess.Board()" object and its methods allow us to evaluate if the game has finished and the reason for it (someone won, the time ended or the user pressed the "Quit" button). These actions lead to the showGameResult state, in which the interface is updated, other tasks related to the game closure are performed and finally it goes back to the stby state.
The startMenu state is a little bit more complex, it starts when the user presses the button "New Game", and consists of a series of steps for the game configuration. To do so another state machine was implemented, a brief diagram of it is shown below:
The purpose of this process is to set up the game parameters which can change for each game, for example the color of the pieces and the difficulty level. The first state is config which launches a form in a new windows where the user has to choose his color (black or white), the game duration (by default 10 min), the type of camera (RPi Camera Module or a USB Webcam) and the difficulty level which is a parameter in Stockfish that can be set by the Python-Chess library with the “configure()” method of the chess engine object.
After completing this process the game starts and the interface will show a responsive board that will update after each turn and display a message with the type of move that was played. After the user makes his move he has to press the clock shown at the bottom left of the interface, this will trigger the vision and chess logic routines explained in the previous modules and also allows to keep track of the time each player takes to make the moves. This cycle will repeat until one of the players achieves checkmate or if the user decides to abandon the game by pressing the “Quit” button.