Manual
Introduction
The Klotski application allows you to play the eponymous game: a sliding block puzzle where the goal is to move a special block to a predefined position. The challenge lies in cleverly maneuvering the other pieces within the game board to make way for the special one, and to succeed in getting it to the final position in the fewest possible moves.
Technologies Used
Name | Version | Description |
---|---|---|
Java | 20 | Environment and programming language used to develop the application. |
JavaFX | 20.0.1 | Platform for client application development, based on Java. |
JFoenix | 9.0.1 | Open-source Java library that implements Google Material Design using Java components. |
Jackson | 2.12.3 | Java library for serializing Java objects to JSON and vice versa. |
JUnit | 5.9.1 | Framework for automated testing of Java classes. |
SceneBuilder | 19.0.0 | Software for building a JavaFX GUI using "drag and drop." |
In the end, it is recommended to consult the attached Javadoc for a better understanding of library integration.
Project Description and Implementation
In the early stages of project development, specifications were discussed and explored with the idea of tackling the design and development phases as linearly as possible.
After completing the specification and design phases (whose "deliverables" are attached in the following sections), the actual development of the application was initiated.
The main idea underlying the implementation of the software's features was to use the concept of "configuration," representing the set of pieces that make up the puzzle and their positions at a given moment (or move).
Graphical Interface and Block Movement
To create the GUI, the JavaFX graphics library and SceneBuilder software were used for easier
arrangement of graphical elements and the subsequent generation of the .fxml
file,
which encodes the interface using JavaFX markup language.
The blocks were implemented by extending the Rectangle
component of JavaFX, allowing
for the management of block movement logic - preventing overlap, ensuring they stay within the game
board's boundaries, and extracting information from attributes provided directly by the library.
To complete the interface, buttons were added, selected from JFoenix components. Each button was associated with a functionality, each of which was implemented through logic triggered by user actions on the GUI.
Possibility to Save the Current State and Restore It
This feature is closely related to the others. To save the current state and allow its restoration once the application is closed and reopened, we decided to keep track of various configurations generated every time a single block is moved. This history is stored in a JSON file, which is updated with each move. The Jackson library was used to handle file writing and reading.
Choosing from Different Initial Configurations
The functionality of changing configuration was associated with some buttons. The selectable
initial configurations are stored within the code.
Please note that changing the configuration results in a reset of the history.
Resetting the Game
Through the dedicated button, you can reset the game by returning to the initial configuration from which you started playing.
Undoing a Move
Using the appropriate button, you can undo one move; this operation is implemented by removing the last configuration from the history and displaying the penultimate one.
Next Best Move
With the dedicated button, you can make the game execute the best possible move starting from the current state of the game when NBM is requested. The logic enabling this functionality is implemented by an external system (link to the script). The connection between the latter and the software was created using two JavaFX classes: WebView, to "map" the content of a web page, and WebEngine, to modify a web page through WebView. With this infrastructure, it was possible to query the external system and process its response. The resulting configuration is stored in the history as a move.
Move Counter
A "counter" is provided to count the moves in a game, which corresponds to the size of the history without considering the initial configuration (this logic applies to all other features).
At the end of the development, code refactoring was performed to enable efficient and rigorous testing, including the use of JUnit (the testing deliverables are available in the following sections).
Download and Install the Software
Jar
To download the program in .jar
format, click on the Windows or macOS button:
Once the .zip
file download is complete, extract its contents to a location of your choice on your device. There will be a directory containing a folder and a file:
-
/klotski_files, which contains the files necessary for game saving and NBM request. It was chosen to allocate them externally because it was not possible to render and use them within the
.jar
file. -
klotski.jar
, the application.
To start the application, double click on the klotski.jar
file. Running the program in this mode is possible after installing the JRE.
Note: macOS
If, when attempting to run the .jar file, the alert 'Unable to open “klotski.jar” because it is from an unidentified developer' appears, you can still run it through: Right-click > Open > Open
IDE
If there are issues with the previous installation method, it is recommended to clone the repository at the link in the upper right corner, open the downloaded project with an IDE (such as IntelliJ), and run the
Main.java
file located at the following path:
src/main/java/com/klotski/app/Main.java
Execution requires the installation of the jdk (preferably version 20).
How to Play

To move a block, simply click on it and move it using the arrow keys or WASD.
To change configuration, simply click one of the numbered buttons to the right of the puzzle.
To request the functions, simply click the corresponding buttons to the left of the puzzle.
Note: NBM may take some time, especially on the first run.
Design Patterns
GRASP
Creator
The Piece
class was designed following the "Creator" pattern.
Configuration
indeed instantiates and aggregates
objects of the Piece
class. Also, Configuration
is contained and instantiated in Game
.
Controller
The Controller
class is simply what it says it is: a "controller," an object responsible for
communication between the graphical interface and the system. This class is responsible for receiving the user inputs provided through the GUI, subsequently invoking functions implemented in other classes that handle the request's logic, and then receiving the results and updating the interface accordingly.
Low Coupling
All classes in this software were designed to limit coupling as much as possible, i.e., the impact that a change to one class could have on the entire project.
High Cohesion
All classes in this software were designed to represent atomic and separate concepts as much as possible.
Pure Fabrication
During the design phase, it was noticed that a class to handle all the logic behind a game of Klotski would be convenient. With this purpose, the Game
class was "fabricated."
GoF
Facade
The Controller
class also serves as an interface for the NBM_Script. In practice, it is the only facade that connects the system with other external actors, which reflects the "Facade" design pattern.
Low Coupling
All classes in this software were designed to limit coupling as much as possible, i.e., the impact that a change to one class could have on the entire project.
High Cohesion
All classes in this software were designed to represent atomic and separate concepts as much as possible.
Pure Fabrication
During the design phase, it was noticed that a class to handle all the logic behind a game of Klotski would be convenient. With this purpose, the `Game` class was "fabricated."
GoF
Facade
The `Controller` class also serves as an interface for the NBM_Script. In practice, it is the only facade that connects the system with other external actors, which reflects the "Facade" design pattern.
Specifications

- View current configuration
- Choose initial configuration
- Move pieces to allowed positions
- View move counter
- Use reset function
- Use undo function
- View "next best move"
- Save the game
- Restore saved game
- Provide "next best move"
- Win
Use Case 1 | |
---|---|
Use Case Name | View current configuration |
Actors | Player |
Description | The player must be able to view the current configuration on the screen. |
Preconditions | - |
Main Scenario | The last configuration stored in the history is displayed to the player. |
Alternative Scenario | - |
Post-Conditions | - |
Notes | - |
Use Case 2 | |
---|---|
Nome dello Use Case | Choose Initial Configuration |
Attori | Player |
Descrizione | The player can select one of four initial configurations to start playing. |
Precondizioni | - |
Scenario Principale | The program sets up the initial arrangement of pieces based on the configuration chosen by the player. |
Scenario Alternativo | The game can start or continue with the current configuration. |
Post-Condizioni | Reset the move counter and the game. |
Note | The choice of the initial configuration can always be made, but the ongoing game will be deleted. |
Use Case 3 | |
---|---|
Use Case Name | Move Pieces to Allowed Positions |
Actors | Player |
Description | The player can move a piece one position per turn to an empty space that can accommodate it. |
Preconditions | There must be an allowed position, i.e., an empty space. |
Main Scenario | The selected piece is moved one position in the direction chosen by the player. |
Alternative Scenario | The selected piece does not move. |
Post-Conditions | Increase the move counter, save the game. |
Notes | - |
Use Case 4 | |
---|---|
Use Case Name | Display Moves Counter |
Actors | Player |
Description | The player must be able to view the number of moves made so far. |
Preconditions | A counter must be present in the graphical interface displaying the number of moves made up to that point. |
Main Scenario | Whenever the player takes an action, the counter is updated and displayed to the player. |
Alternative Scenario | - |
Post-Conditions | - |
Notes | - |
Use Case 5 | |
---|---|
Use Case Name | Use Reset Function |
Actors | Player |
Description | The player can reset the game using a dedicated button. |
Preconditions | - |
Main Scenario | At any time, the player can choose to reset the game by pressing the "reset" button. Pieces must be arranged in the initial configuration related to the game they were playing. |
Alternative Scenario | If the player has not made a move yet, the reset does nothing. |
Post-Conditions | Reset the move counter and the game. |
Notes | - |
Use Case 6 | |
---|---|
Use Case Name | Use Undo Function |
Actors | Player |
Description | The player can choose to undo a move using a dedicated button. |
Preconditions | At least one move must have been made before invoking the functionality. |
Main Scenario | The arrangement of the pieces reverts to the previous configuration relative to the current one. |
Alternative Scenario | No modifications are applied to the game state, and the player is notified that there are no moves to undo. |
Post-Conditions | Decrease the move counter, save the game. |
Notes | The player can undo as many moves as they wish, going back through the game's history to the initial configuration. |
Use Case 7 | |
---|---|
Use Case Name | Display "Next Best Move" |
Actors | Player |
Description | The player sees a configuration representing the best move compared to the previous configuration. |
Preconditions | The player must be connected to the internet. |
Main Scenario | Whenever "Next Best Move" is requested, one piece at a time will be moved to achieve victory in the fewest possible moves. |
Alternative Scenario | The message "NBM not available, connect to the Internet" is displayed if the player is not connected. |
Alternative Scenario | The message "Error loading NBM" is displayed if something goes wrong. |
Alternative Scenario | The message "Loading NBM..." is displayed if the player requests the NBM again before receiving it. |
Post-Conditions | Increase the move counter, save the game. |
Notes | - |
Use Case 8 | |
---|---|
Use Case Name | Save the Game |
Actors | Player |
Description | The player must be able to save the game. |
Preconditions | The player has taken some action. |
Main Scenario | Whenever the player performs an action that affects the arrangement of the pieces (move, undo, reset, or choose the initial configuration), the game must be saved so that if the program is closed, the game can be resumed upon the next launch. |
Alternative Scenario | - |
Post-Conditions | - |
Notes | The game is represented by all configurations generated up to that point (plus the initial configuration) and, consequently, by the move counter. |
Use Case 9 | |
---|---|
Use Case Name | Restore Saved Game |
Actors | Player |
Description | When the player reopens the application, the game loads the last saved configuration. |
Preconditions |
|
Main Scenario | The player opens the application and views the last saved configuration from when the game was last closed. |
Alternative Scenario | - |
Post-Conditions | - |
Notes | - |
Use Case 10 | |
---|---|
Use Case Name | Provide "next best move" |
Actors | NBM_Script |
Description | The external system NBM_Script calculates the NBM (Next Best Move). |
Preconditions | The player must be connected to the internet. |
Main Scenario | The external system calculates the NBM and provides it. |
Alternative Scenario | The external system fails to calculate the NBM for some reason. |
Alternative Scenario | The external system does not receive the request or cannot send a response due to a connection interruption. |
Post-Conditions | The NBM must be processed and displayed. |
Notes | - |
Use Case 11 | |
---|---|
Use Case Name | Win |
Actors | Player |
Description | The player must be able to win. |
Preconditions | The player must have moved the special piece to the winning position (bottom center). |
Main Scenario | The player is notified that they have won. |
Alternative Scenario | The player, with the current move, has not reached the winning position with the special piece. |
Post-Conditions | The move counter is reset, and the game is reset. |
Notes | - |
Design
Domain Model

Design Class Model
.png)
Sequence Diagrams
System Sequence Diagram

Internal Sequence Diagrams
move(piece, keyCode)
The numbered sequence within the alt
constructs should not be taken as strict, as they are executed alternatively but indicative.

change_configuration(alternative_configuration)
The numbered sequence within the alt
constructs should not be taken as strict, as they are executed alternatively but indicative.

undo()
The numbered sequence within the alt
constructs should not be taken as strict, as they are executed alternatively but indicative.

reset()

request_NBM()
The numbered sequence within the alt
constructs should not be taken as strict, as they are executed alternatively but indicative.

Test
JavaDoc
Click to view the JavaDoc