Off The Rails is a simulator for a model railroad that can be used to help visualize operating systems concepts like multi-tasking, racing conditions, and interrupt processing. Users will be presented with a screen on which they can add and control various trains on a rail yard layout of their choosing. Many users will be able to collaborate on the same layout, and it will be up to them to control the trains and ensure that things don't go off the rails.
In the past, other students at St. Norbert College have used a physical model railroad table, referred to as the Computer Controlled Railroad (CCR), to try to instruct others on these concepts. My task is to simulate the behavior of this table so that students can continue to do work on the CCR, but without the constraints of a fixed layout and the concerns of damaging the models. If needed, my simulator will also be able to plug into the actual CCR and control it, and the layout of the actual CCR will come as a layout that is available to users be default. For those interested, the detailed project specifications can be found here.
Project Scope
Off The Rails will manifest itself as a client-side application that the user can run on a desktop or laptop. It will have an "editor mode" and a "run mode", which users can switch between to define their track layouts and to run their trains on them. Users will be able to save, load, and edit their rail yard layouts using the "editor mode". In cases where multiple train engineers would like to work together on the same layout, there will be a networking mode where a host will open up a "room" with a layout that other users can join. The user, of course, is also able to run the simulator by themself with multiple trains as well. Finally, the simulator will have a fully functional API that will allow other programs to send and receive information to and from the simulator. This would, for example, allow you to write a program that would drive the train for you rather than needing to drive it yourself. Or, this API could be used to create a meta-programming language, sort of like an instructional block-based language, that would allow users to drive the trains programmatically.
Requirements and Subtasks
As you can see in the project specification, there are a number of requirements that this simulator must meet. I will now list these, along with the sub-tasks that will be required to make them functional. They are grouped together in respect to their areas of concern to the overall simulation application. Each requirement has its sub-tasks listed in a sub-list under its main bullet point:
Layout
Design a track definition protocol so that users can define their own layouts.
Define a "Rail" object that houses the information about the rail, such as its orientation, max speed rating, location, next and previous neighboring rails, and any additional features such as train detection sensors and turnout switches.
Create a data structure to house the layout's rails in a logical and efficient manner. My initial thought is to implement rails in a sort of queue, where each rail has references to its neighbors.
Figure out how the world beneath the rails works. I need to determine if the rails are constrained to some sort of grid or if they are allowed to be placed wherever the user wants in the layout.
Depending on the implementation of the last point, I need to implement a file structure that will consistently persist all of the rails and that can be used to recreate the data structure linking them all together.
Develop a track editor that allows users to design their own layouts
Complete all of the sub-tasks listed under the last major point
Create a way that the user can place rails into the world and connect them together
Create a way that the user can place trains, sensors, and turn switches
Allow the manipulation and deletion of already-placed entities in the layout.
Create an interface that allows the user to intuitively place these things into the layout
Layout designs can be saved, loaded, and modified.
Create the rails and the file structure that allows them to be persisted to the system, and use these to save the layout design to a file on the user's system.
Create a way to pull information from previously saved files and use it to populate the layout in the simulator. From here, users can open it up to edit again and save once more, or they can run the simulator with the loaded layout.
When it comes to the networking later that will allow multiple users to run trains on the same layout, these saved files will need to be able to be uploaded to a central place and downloaded to all of the clients, so it displays the layout information in the same way.
A layout supports turnout switches and train detection sensors.
Come up with a protocol for how the train can interact with these. The train will need to be able to send information to the turnout switches and receive information from the train detection sensors.
Define a way in which these entities can be placed in the layout.
Strongly define the behavior on which each of these works, so they can be placed anywhere in the layout and be expected to behave consistently.
For example, can a turnout only switch between two tracks, or more than that? Are the turnout and sensor their own objects, or are the integrated into the rail object?
Trains
Users can adjust a train's speed, direction, lights, horn, etc. as well as switching the direction of the turnouts
Design a train object containing the information listed above
Define a protocol through which users can modify the train object's data.
Define how sensors and turnouts interact with the trains
Define how users interact with turnouts. Choose if the trains themselves control the turnouts or if the users do.
Users will probably control turnouts through trains, so they will issue a command to the train and the train will request for the turnout to change.
Constrain in-working-order trains to the tracks laid out above.
Detect collision and derailment
Create a sort of physics engine to control the train.
Define speed limits or rail speed ratings to determine whether a train should derail or not
Check along the entire length of the train to see if it has run into something else or if something has run into it and respond accordingly
This might also derail the train if hit by another train or other object
Create animations or other visual representations of these problems occurring to use in the simulator
Support multiple trains
Create a sort of supervisor/updater to keep each of the trains up to date as they make their way around the layout
This could be in the form of an update loop or a game loop
Make sure instances of trains are separate from each other, but can interact with each other in the physics engine as listed above.
Design an interface in which the user can select between the different trains in the layout and control them independently
Simulate error conditions such as broken trains and hardware failure
Provide a control in the simulator/editor that allows the user to turn these error conditions on or off, (on by default)
This is just if they want to run the simulator without these problems interfering
If errors are enabled, have a random, but small, chance that turnouts will fail to switch or that sensors will not convey information to the trains that are passing of them.
Application
Develop a graphical interface that dynamically shows the current state of the CCR.
Create a way to visually represent the rails, trains, turnouts, and sensors
Create sprites and animations for each, potentially
Animate the trains moving along the tracks and their state, whether they are operating normally, have collided with something, are derailed, etc.
Develop a simple interactive interface that can run the simulator
Create a map of possible actions the user can do to interact with the system
Decide how the information available to the user is laid out
For example, do the users have a panel containing the information of all of the trains in the layout where they can manipulate them, or does the user select/click on each train in order to control it individually?
Make the interface communicate with the data structures of the rails, trains, turnouts, and sensors
Allow the user to save the current state of the simulator, or open a previously saved state
Networking
Allow multiple train engineers to remotely control trains on the same layout
Create a networking protocol to allow one user to host their layout and for others to join them on that layout.
Figure out a way to share layout maps between users
Figure out a way for users to connect to each other
I am thinking that the host launches a "room" that can be accessed using a four-digit code, and choose a layout map to upload to a server. When users enter this four digit code into a connection control, it connects to the server and hashes the code to the IP address of the host. The host's layout map is also downloaded to the application of the user that connected so they have a consistent view with the host.
Connect the users simulators together so that the commands they issue are shared among all of the users connected with the host.
Account for connection errors and network latency
Application-Level-Communications
Develop an API that allows application programs to send and receive information to the simulator.
Define what kind of information should be sent in and out
Define what kind of behavior sending information in to the simulator can have. Can it create trains, rails, etc? Can it control existing trains?
Define what information about the simulator's state should be sent out via the API
Create a consistent structure and documentation for the API so it is useful to those who need it.
Determine how much of the application itself should make use of this API to control its inner-workings in order to standardize behavior in reaction to data.
Define how others are able to communicate with this API
Make this API consistent with the abilities of the original CCR so that the simulator is able to control the CCR
Consider a simple meta-programming language to develop programs that control trains in a batch mode.
Design what sort of actions would be useful in a meta-programming language. For example, would it be useful to have a "function" to make train x activate turnout y?
Define the syntax of this language. Is it block-based, command-driven, etc?
Define the scope of the language. Can it control the simulation a train at a time? Does it control the entire thing, with all of the components in the layout being children that it can also access?
Hook this language into the API so that it can actually control the simulation
Please note, this is just a rough interview of how I believe the project will go. For more detailed information on the actual progress of the project, please see my blog.