1. Trainspotting
  2. Trainmonitoring
  3. CCHAT
  4. Workers

Lab 1: Trainspotting


Lab description

In this assignment you will write a program to control two trains. The purpose is to write the program so that the trains move relatively independently of each other, but without colliding. Instead of a real railway, we have a simulator, where one can control the speeds of trains and change rail switches. The simulator gives a signal when a train passes sensors suitably placed on the tracks. It is part of the assignment to decide where sensors should be placed to give sufficient information for your program. The map without sensors looks as follows.

Programming language and environment

This lab assignment must be developed in Java.

In order to make sure you are using the right versions of Java and the train simulator, you should type the command

setup_course tda381

on Chalmers GNU/Linux machines.

If you wish to work on this assignment on your own computer, then you will need to build and run the simulator locally. We do not recommend this, since it may not be straightforward, especially if you are using Windows.

See the computing resources page for further instructions.


Your assignment is to write a program that controls the trains. The trains should run simultaneously between the two stations (note that each station has two tracks). It is important that the trains are able to move at the same time, and be as independent from each other as possible, without crashing. At the stations the trains should stop and then wait 1 to 2 seconds. The trains should run forever between the stations.

In the beginning there are no sensors on the tracks. You must decide where to place sensors so that the control program gets the necessary information.

The program that you deliver should work as follows. Each train should be controlled by an independent train program, which runs in its own Java thread. Train programs cannot communicate with outside world by anything else than acquiring and releasing semaphores. In particular, no shared variables should be read or changed by the train programs. Also, both trains must use the same train program, and the behaviour of a train cannot depend on its train id. For example, the track that a train chooses cannot not depend on its train id.


Train simulator

The simulator is called tsim; use it as follows:

Map editor

The train simulator tsim also works as a map editor.

You need to get your own copy of the map in order to be able to add the sensors. The map you will be working on is that shown above. The map file is included in the archive in the downloads section.

You modify the map with tsim The figure below shows how to use tsim. You should only select the sensor button in the tools window (the small T-like symbol) and then use the mouse to place sensors on the track.


You may start tsim and interact with it using commands on standard input. Try for example the commands

SetSpeed 1 20
SetSwitch 17 7 RightSwitch

and see what happens. (The second command is necessary for the train to survive the first switch which initially is set in the wrong direction). We provide the Java library to handle the communication with tsim, which lets you change the speed of the trains and the state of the switches in a more convenient way (see next section).

Here are some things to note about the simulator:

Program/Simulator interaction

The simulator and your program run as separate OS processes. They use pipes to communicate. The Main class provided in the skeleton code takes care of joining together the pipes of your solution in Java with the tsim simulator.

All commands between the your program and the simulator are sent line-by-line as text strings, as you saw above. To aid you in your assignment we provide you with a Java library (TSim) that implements the protocol tsim is using. You must use this Java library. The package provides you with an interface to control the behaviour of the trains and switches. You can view the JavaDoc documentation of this library.


You cannot create instances of TSimInterface using its constructor, since it is private. Instead you use the static method getInstance() that creates an instance of the class if that has not already been done (singleton pattern).

TSimInterface tsi = TSimInterface.getInstance() ;

Useful classes

try {
catch (CommandException e) {

  /* If a command failed then something bad has
     happened and we probably don't want to
     continue executing */


Download material for the lab

To get started, you need the skeleton code package.

Getting started

You should implement your solution in the file. We provide a Main class which takes care of loading the simulator and connecting it to your solution. You shouldn’t need to change this file. This entry point expects at least 3 command line arguments:

  1. map file

  2. speed of train 1

  3. speed of train 2

  4. simulator speed [optional]

Using the command line

To build your solution, you can simply run the following command:

make all

from the root directory of the project. This will place the class files in the bin folder.

You can then run your solution with:

java -cp bin Main 5 15

Using Eclipse

You can also open the files as an Eclipse project:

  1. Extract the trainspotting folder into your workspace directory.
  2. In Eclipse, choose New → Java Project. Give it the exact name trainspotting to use the existing sources.

When running or debugging the Main class in Eclipse, you will need to specify the command-line arguments via the Run Configurations dialog.

Tips and tricks


It was stated above but may be stated again: reasonable code quality is expected. You are programmers. Programming should be an art to you. The quality of your code will be vital for its reuse and maintenance.

Common reasons for rejection

Using polling/busy waiting for synchronization is a common mistake that leads to submissions being rejected.

Here are some examples of polling/busy waiting in pseudo code. Loops that behave similarly to the situations below (where the dots do not include any blocking wait) are considered as polling.

while (e) { // POLLING!

Using a blocking operation within a loop is not considered as polling

while (e) { // NO POLLING!

provided that it is not the case that that the waiting process is woken up from its wait at regular. Thus, the following example is also an instance of polling:

obj o;

process a {   
  while (true) {

process b {  // POLLING!
  while (e) {