This Dezyne example is Hans Kuppens’s submission for the Dezyne Challenge 2016.
The goal of this Dezyne modelling example is to create an interface to make a puzzle with 6 balls which have to roll through a labyrinth, with 14 gears, to the end destination. The route of a ball will be decided by the stand of the gears which will be passed on its way.
The design according to the architecture diagram is shown in the following figure:
The CInputHandler provides the only “provided interface” of the Dezyne system to the application. This interface sends from the application screen “MainForm” the keyboard events to the CInputHandler module. While MainForm_Load() the Dezyne components will also be installed and initialized through this interface. Contrariwise, while MainForm_FormClosing() the Dezyne components will be terminated (The removing we will leave to the garbage collector). Originally the idea was to realize a separate component for the startup behavior, but eventually the CInputHandler has remained for this task.
The CBallControl actually determines the process of the puzzle, the “workflow”. On this level the 6 balls will be started one for one, and it will be monitored if a ball has fallen in an ambush. The view from the main screen is being regulated trough HMainScreenControl. It is possible to start over when the puzzle ended.
Every BalAssy is responsible for the accomplishing of the entire route of one ball, and reports to CBallControl if the ball is ready for the next step or is arrived in one of the “Error” of “Pocket” end stations.
The CBallSwithBoard gets the information from the gears (Gears) to determinate the route of the ball. This component will be explained later.
The “rolling” of the ball through the labyrinth is being executed by two components: CBall and CBallStepper.
This easy could have been a combined component, but several tasks are divided: The CBall is able to independently accomplishing parts of the route, but it can’t make choices. This task lies with the CBallStepper, which therefore needs a required interface to the Gears (through CBallSwitchBoard). The HBallData component calculates the route in pixel coordination, and ensures that the ball is shown on the screen in the labyrinth.
In the GearSystem subsystem are two CGearControl components in charge: RedGearControl and BlueGearControl (obvious for the red and the blue gears respectively). Actual these components are not doing much different than the input commands distributing to the 8 red and 6 blue gears; at the gears there not really a complex “workflow”.
Each GearAssy is responsible for the rotating of 1 gear, and performs the assignments of the controlling CGearControl component without any feedback trough reply of out events. The turning of a gear takes some time (this was a deliberate choice) and because of the lack of the feedback it is able to receive a new assignment while it’s turning. Then the direction of rotation just turns around.
The group CGearSwitchBoard components supplies a provided interface to the BallSystem subsystem, which will be explained later. Through this interface a ball can inform to the stand of the gear for his route: to the left or to the right. It is possible that the gear is still rotating. Then the ball has to wait till the end position is reached. The other way around the ball is able to block the gear with Lock(), to provide that the gear starts turning when the ball “is still in it”. When the ball is leaving the gear it’ll abolish the block with Unlock().
The turning of a gear is performed by the CGear component.
This component has two provided interfaces, one is intended for the CGearControl and the other one is intended for the CGearSwitchBoard component. The HBallData component measures the stand position in pixel coordination’s, and ensures that the gear is shown on the screen while turning in the labyrinth.
CBallSwitchBoard and CGearSwitchBoard components
In this design of the puzzle there are 6 balls which have to roll through the labyrinth, with 14 gears, to the end destination. The route of a ball will be decided by the stand of the gears which will be passed on its way. In principle there are 6×14=84 interfaces needed for this! This problem is obviated by the “SwitchBoard” pattern, comparable with a telephone exchange.
Through CBallSwitchBoard every ball can dynamically get an interface with every gear, trough one static interface (The one between CBallSwitchBoard and CGearSwitchBoard). The ball does a Connect(eGearID) request which eventually will be offered to all CGears. Only the CGear, which recognizes itself to the parameter eGearID, does a reply(true) and establishes the connection mode. The functional state of CGear propagates with a GetState() back to CBallSwitchBoard, so that verification is actually possible. It matters to keep the transactions short, because as long as the line is busy the other balls can’t make a connection.
This solution is highly scalable: By putting CGearSwitchBoard in cascade one after the other (2 levels of each 1:4 demultiplex) 16 ports will be available. This principle could also have been with CBallSwitchBoard.
How to solve the puzzle
The operation is very simple. At the left are two buttons (red and blue) with which the gears are operated. The green button at the right side is used to play the next ball. Balls have to be played one for one; the next ball can only be played when all the other balls stand still again (thus, you can’t keep 6 balls close to each other and pilot them through the labyrinth.
With the green button a new attempt is started when the previous attempt has ended (successful or unsuccessful).
The solution of the puzzle
Just try it yourself. You can download the DezyneInThePocket game
To install the game on your computer you open the program .publishsetup.exe. and to play you open the DezyneInThePocket.application
You can download the example in a zip-file from here.
Note that all of the diagrams included in this document have been produced in and exported from Dezyne. The System View and State Charts are part of the Dezyne editor. The Sequence Trace has been produced using the Dezyne simulation engine.
The application is developed with Dezyne version 2.1.1 (build 45). The generated code is C#, which is integrated in an application with MicroSoft Visual C# 2010 Express.
The sourcefiles are stored in the following directories:
'DezyneInThePocket' → Root directory with generic project files
'.DezyneWorkspace' → All the Dezyne models from the project (*.dzn)
'.DezyneGenerated' → All the generated code from the Dezyne models (do not edit!)
'.DezyneHandwritten' → All handwrited code with Dezyne interfaces
'.DezyneRuntime' → The Dezyne runtime files
'.Resources' → All graphic objects, in the shape of PNG bitmaps
'.Properties' → Other generic project files
'.bin' → generated binary files
'.obj' → generated binary files
'.publish' → generated distribution files
A Dezyne file (*.dzn) can have different content, the First letter of the filename is indicative for the content of the file:
1. Because I found out quickly that there were only a handful of rules (and that there won’t be generated any code, at least with C#), I have repeatedly added the declaration to the interface files in the handwritten components (I*.dzn).
If you have questions that weren’t by this Guide,
let our support team help you out.