| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the documentation of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:FDL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Free Documentation License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Free |
| ** Documentation License version 1.3 as published by the Free Software |
| ** Foundation and appearing in the file included in the packaging of |
| ** this file. Please review the following information to ensure |
| ** the GNU Free Documentation License version 1.3 requirements |
| ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| /*! |
| \example sudoku |
| \title Qt SCXML Sudoku Example |
| \ingroup examples-qtscxml |
| \brief Presents the use of SCXML in a sudoku game. |
| |
| \e {Sudoku} demonstrates how an SCXML file may be used in a game. |
| |
| \include examples-run.qdocinc |
| |
| \section1 Sudoku Features |
| |
| \image sudoku.png Screenshot of the Sudoku example |
| |
| Our sudoku contains the following features: |
| \list |
| \li Initially and when the game ends, the sudoku |
| enters the \c idle state. In that state the players |
| can see if their last game finished successfully or not. |
| The state machine is then in one of two child states |
| of the \c idle state: \c solved or \c unsolved, |
| respectively. In the \c idle state the players |
| can also choose the sudoku grid they would like to solve. |
| The grid is disabled and the user interaction |
| is ignored. |
| \li After players click the \uicontrol Start button, the sudoku |
| enters the \c playing state and is ready for the user |
| interaction on the board. |
| \li When the game is in the \c playing state and the players |
| click the \uicontrol Stop button, the game ends |
| and enters the \c unsolved child state of the \c idle state. |
| If the players have solved the current puzzle successfully, |
| the game automatically ends and enters the \c solved child state |
| of the \c idle state indicating success. |
| \li The board consist of 81 buttons, laid out in a 9x9 grid. |
| The buttons with initial values given remain disabled |
| during the game. The players can only interact |
| with buttons initially empty. Each |
| click on the button increases its value by one. |
| \li During the game the \uicontrol Undo button |
| is available for the players' convenience. |
| \endlist |
| |
| \section1 SCXML Part: Internal Logic Description |
| |
| The \e sudoku.scxml file describes the internal structure of |
| the states the sudoku game can be in, defines the transitions |
| between states, and triggers the appropriate script |
| functions when the transitions take place. It also |
| communicates with the GUI part by sending events and listening |
| to the upcoming events and reacting to them. |
| |
| We use the ECMAScript data model: |
| |
| \quotefromfile sudoku/sudoku.scxml |
| \skipto scxml |
| \printuntil ecmascript |
| |
| We declare the following variables: |
| |
| \printuntil </datamodel> |
| |
| \table |
| \header |
| \li Variable |
| \li Description |
| \row |
| \li \c initState |
| \li Holds the initial state of the current game. It is a |
| two-dimensional array of 9x9 cells that contain initial sudoku |
| numbers. The value of zero means the cell is initially empty. |
| \row |
| \li \c currentState |
| \li Holds the current state of the game being played. It is |
| similar to the \c initState variable and initially |
| contains the same content. However, when the players start |
| entering the numbers into the empty cells, this variable |
| is being updated accordingly, while the \c initState variable |
| remains unchanged. |
| \row |
| \li \c undoStack |
| \li Holds the history of players' moves. It is a vector of |
| the cells' coordinates that were touched last. Each |
| new modification during a game adds a pair of |
| x and y coordinates to that vector. |
| \endtable |
| |
| The variables above are shared with the script helper functions |
| defined in the \c sudoku.js file: |
| |
| \printuntil sudoku.js |
| |
| We call some of the functions defined there |
| when taking transitions or in reaction to the |
| events sent by the GUI. |
| |
| All the possible states mentioned before are defined in a |
| root state \c game. |
| |
| \printuntil idle |
| \dots 12 |
| \skipto id="unsolved" |
| \printuntil playing |
| \dots 12 |
| \skipto /^\ {8}<\// |
| \printline state |
| \dots 8 |
| \skipto /^\ {4}<\// |
| \printline state |
| |
| When the sudoku example is started, the state |
| machine enters the \c game state and stays in this |
| state until the application exits. When entering this |
| state, we raise internally the \c restart event. |
| This event is also being raised whenever the players |
| change the current sudoku grid or when they start |
| the game by pressing the \uicontrol Start button. |
| We do not want to send it when they have finished |
| the current game because we still want to show the |
| filled grid from the last game play. So, this event |
| is being raised from three different contexts |
| and is captured internally once in a targetless |
| transition of the \c game state: |
| |
| \quotefromfile sudoku/sudoku.scxml |
| \skipto <transition event="restart"> |
| \printuntil </transition> |
| |
| When we catch the \c restart event, we call |
| a helper \c restart() script method, defined in the \c sudoku.js |
| file and raise internally an additional \c update event. |
| |
| \quotefromfile sudoku/sudoku.js |
| \skipto restart |
| \printuntil } |
| |
| The \c restart() function assigns the \c initState into the \c currentState |
| variable and clears the \c undoStack variable. |
| |
| The \c update event is raised internally whenever we want to notify the GUI |
| that the grid contents have been changed and that |
| the GUI should update itself according to the passed values. This event |
| is caught in another targetless transition of the \c game state: |
| |
| \quotefromfile sudoku/sudoku.scxml |
| \skipto <transition event="update"> |
| \printuntil </transition> |
| |
| We send the external event \c updateGUI, |
| which is being intercepted in the \l {cpp}{C++ code}. |
| The \c updateGUI event is equipped |
| with additional data, specified inside \c <param> |
| elements. We pass two parameters, which |
| are accessible externally through the |
| \c currentState and \c initState names. |
| The actual values passed for them |
| equal the datamodel's \c currentState |
| and \c initState variables, respectively, which |
| are specified by the \c expr attributes. |
| |
| \quotefromfile sudoku/sudoku.scxml |
| \skipto idle |
| \printuntil </state> |
| |
| When in \c idle state, we react to two |
| events, which may be sent by the GUI part: |
| \c start and \c setup. Whenever we receive the |
| \c start event, we just transition to the \c playing |
| state. When we receive the \c setup event, we |
| expect that the GUI part has sent us the new grid |
| to be solved. The grid's new initial state is expected |
| to be passed through the \c initState field of |
| \c _event.data. We assign the passed value to the |
| \c initState variable defined in our datamodel and |
| restart the grid's contents. |
| |
| \skipto playing |
| \printuntil </transition> |
| \dots 12 |
| \skipto </state> |
| \printline </state> |
| |
| Whenever we enter the \c playing state, we reset |
| the grid's contents since we could have been still |
| showing the contents from the previous game play. |
| In the \c playing state we react to possible |
| events sent from the GUI: \c tap, \c undo, and \c stop. |
| |
| The \c tap event is sent when the players |
| press one of the enabled sudoku cells. |
| This event is expected to contain additional data |
| specifying the cell's coordinates, which are passed |
| through the \c x and \c y fields of \c _event.data. |
| First, we check if the passed coordinates are valid |
| by invoking the \c isValidPosition() script function: |
| |
| \quotefromfile sudoku/sudoku.js |
| \skipto isValidPosition |
| \printuntil } |
| |
| We ensure the coordinates are neither negative nor bigger than our grid. |
| In addition, we check if the coordinates point to an |
| initially empty cell, since we can not modify |
| the cells initially given by the grid description. |
| |
| When we have ensured the passed coordinates are correct, |
| we call \c calculateCurrentState() script function: |
| |
| \quotefromfile sudoku/sudoku.js |
| \skipto calculateCurrentState |
| \printuntil } |
| |
| This function increments the value of the passed |
| grid's cell and adds the new move to the |
| undo stack history. |
| |
| Right after the \c calculateCurrentState() function |
| finishes its execution, we check whether the grid is |
| already solved by calling the \c isSolved() script function: |
| |
| \quotefromfile sudoku/sudoku.js |
| \skipto isOK |
| \printuntil return true |
| \printuntil } |
| \skipto isSolved |
| \printuntil return true |
| \printuntil } |
| |
| The \c isSolved() function returns \c true if the |
| grid is properly solved. Since we need to check |
| each row, each column, and each 3x3 square, we define |
| the \c isOK() helper function. This function takes |
| the vector of numbers and returns \c true if the passed vector |
| contains unique numbers and no number equals zero, meaning |
| there is no empty cell. The main loop of the \c isSolved() is invoked |
| nine times. In every iteration, we construct three vectors of numbers |
| representing a row, a column, and a square of the grid and call \c isOK() |
| for them. When all 27 vectors are OK, the grid is solved properly |
| and we return \c true. |
| |
| Coming back to our SCXML file, in case \c isSolved() |
| returns \c true, we raise the \c solved event internally. |
| The last instruction in case of a proper move is to raise |
| the \c update event, since we need to notify the GUI |
| about the grid's change. |
| |
| \quotefromfile sudoku/sudoku.scxml |
| \skipto id="playing" |
| \printline playing |
| \dots 12 |
| \skipto undo |
| \printuntil </state> |
| |
| When in the \c playing state, we also react to the \c undo |
| event sent from the GUI. In this case, we call the \c undo() |
| script function and notify the GUI about the need of an update. |
| |
| \quotefromfile sudoku/sudoku.js |
| \skipto function undo |
| \printuntil } |
| |
| The \c undo() function removes the last move from |
| the history, if there was any, and decrements the current value |
| for the cell described by the coordinates taken from this move. |
| |
| The \c playing state is also ready for the \c stop |
| event sent by the GUI when the players press the \uicontrol Stop |
| button. In this case, we simply activate the \c idle state. |
| |
| In addition, we intercept the \c solved event |
| sent internally and activate the \c solved state in this case. |
| |
| \target cpp |
| \section1 C++ Part: Constructing the GUI |
| |
| The C++ part of the application consists of a |
| \c MainWindow class which constructs the GUI and glues it with the SCXML part. |
| The class is declared in \e mainwindow.h. |
| |
| \quotefromfile sudoku/mainwindow.h |
| \skipto MainWindow |
| \printuntil }; |
| |
| The \c MainWindow class holds the pointer to the |
| \c {QScxmlStateMachine *m_machine}, which is the state machine |
| class automatically generated by Qt out of the \c sudoku.scxml file. |
| It also holds the pointers to some GUI elements. |
| |
| \quotefromfile sudoku/mainwindow.cpp |
| \skipto MainWindow |
| \printuntil { |
| |
| The constructor of the \c MainWindow class |
| instantiates the GUI part of the application |
| and stores the pointer to the passed state machine. |
| It also initializes the GUI part and glues the |
| GUI part to the state machine by connecting |
| their communication interfaces together. |
| |
| \skipto clicked |
| \printuntil }); |
| |
| First, we create 81 buttons and connect |
| their \c clicked signal to a lambda expression |
| that submits the \c tap event to the state machine |
| passing the button's coordinates. |
| |
| Later, we add some horizontal and vertical lines |
| to the grid in order to group buttons in 3x3 boxes. |
| |
| \skipto clicked |
| \printuntil }); |
| |
| We create the \uicontrol {Start / Stop} button and |
| connect its clicked signal to a lambda expression |
| which submits the \c stop or \c start event |
| depending on whether the machine is in \c playing state |
| or not, respectively. |
| |
| We create a label informing whether the grid is solved |
| or not, and an \uicontrol Undo button, which submits the |
| \c undo event whenever it is clicked. |
| |
| \skipto clicked |
| \printuntil }); |
| |
| Then we create a combobox that is filled with |
| grid names to be solved. These grids are |
| read from the \c :/data directory of the application |
| compiled-in resources. |
| |
| \skipto currentIndexChanged |
| \printuntil setInitialValues |
| |
| Whenever the players change the grid in the combobox, |
| we read the grid contents storing it in the |
| variant map under the \c initValues key as a |
| list of lists of int variants and we submit the |
| \c setup event to the state machine passing |
| the grid's contents. Initially, we read the first |
| available grid from the list and pass it directly |
| to the sudoku state machine as the initial grid. |
| |
| \skipto connectToState |
| \printline playing |
| \dots 8 |
| \skipto }); |
| \printuntil connectToEvent |
| \dots 8 |
| \skipto }); |
| \printline }); |
| |
| Later, we connect to the signals that are being sent |
| whenever the machine enters or leaves the \c playing |
| or \c solved states, and we update some GUI parts accordingly. |
| We also connect to the state machine's \c updateGUI event |
| and update all the buttons' values according to the passed cells' states. |
| |
| \quotefromfile sudoku/main.cpp |
| \skipto #include |
| \printuntil /\}$/ |
| |
| In the \c main() function in the \c main.cpp file, we instantiate the |
| \c app application object, \c Sudoku state machine, |
| and \c MainWindow GUI class. We start the state machine, |
| show the main window, and execute the application. |
| */ |