Revision control
++ // Copyright (C) 2023 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \example sudoku
++ \title SCXML Sudoku
++ \examplecategory {Data Processing & I/O}
++ \ingroup examples-qtscxml
++ \meta tag {state machine}
++
++ \brief Demonstrates the use of separate javascript file with SCXML.
++
++ \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 list of
++ the cells' coordinates that were touched last. Each
++ new modification during a game adds a pair of
++ x and y coordinates to that list.
++ \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 list of numbers and returns \c true if the passed list
++ 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 lists of numbers
++ representing a row, a column, and a square of the grid and call \c isOK()
++ for them. When all 27 lists 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.
++ */