Thursday, 31 October 2019

One program to bind them all

A couple of years ago I completed a B.Sc. with the Open University. I started this is 1974 so it took me some time, although I took a 33 year break where technology changed a bit! In 1975 they taught me Basic but at the time I was working as a trader in the City so didn't see the use until I started writing software for my own trading rooms. As a result of this, after 20 years as a trader I broke out and started my own software company.  I have now spent the last 34 years making a living writing software or managing software projects.

My final year at the OU comprised a project management course. I used this to develop a three tier cloud based car routing system for US based freight cars. This comprised a back end "Key-Value" database (in the cloud), a dedicated web server and a mobile phone front end where all the output looked like conductor generated switch lists. Subsequent to finishing the course, I disposed of all my US outline HO stuff and went into UK based N gauge. I found that the steam locos in this gauge were extremely fragile and I had to return more than I kept, eventually, disposing of all of that stock as well. Due to restrictions on space, once my 93 year old mother in law took over my hobby room, I moved into my current Marklin set up. I am now on my second layout and have developed a train management program to define random trains within the scope of a set of defined objects.

As I am getting on with my layout almost too quickly - I can spend up to 5 hours, 5 days a week, if I care too, I have decided to go back and hone the software and, in the process, describe it for anyone out there that would be interested. If you are a keen programmer then pin your ears back; if not, then have a go. You may learn something - smile.

Background software

The backbone of an software is the programming language that is used in the development. Although this shouldn't change how the program looks and acts, it has a bearing things like speed of development, complexity and so on. Some languages are highly complex making the likelihood of bugs to increase. I have been committed to developing using Object Oriented (OO) techniques in 29 out of the 43 years that I have been able to program. My development language of choice for OO is Smalltalk - a development environment created at Xerox Parc in the early 1980s. There are a few Smalltalk environments available but for many years I have been committed to that which started out at IBM's VisualAge and is now marketed and developed by Instantiations, in Oregon, USA. In order to develop web based software, I use the Seaside framework that is popular across a wide variety of Smalltalk dialects.

Ever since I had my own model shop and had to develop complex sales and web systems for that, I have used what is known as a "Key-Value" database (KV). This, as the title suggests, stores an object (the value) into a "bucket"under a keyword. It gets more complex than that but not much more. Originally, I developed my own ad-hoc version. For my OU course, I used a 3rd party package called Riak. This has a drawback for my ongoing use in that it requires a Unix box to run. Whilst I could maintain one of these during my OU course, I didn't want to have to keep it going permanently. It wasn't helped by the company that owned Riak shutting down. I returned to my original idea and developed, what I call, my Tiny Key Value DB - TinyKV. This is an extremely compact version of a KV written wholly in Smalltalk and thus easily integrated into my proposed software.

The software with no name

Normally, software packages have names but as this is a personal thing, I haven't got round to giving it one. Let's call it PVDB (Pennstadt-Valdorf Database)? So, what does it do.

Using a web interface, the software generates a string of trains that "could" be run over my current railway. I say "could" because there is no compulsion, unlike my OU software where, if you didn't run a train, all of the freight cars would be in the wrong place when the next one came along! So, it suggests a train. If you like it, you run it, if you don't you skip it. There is an option to record the train but this is so you can run a train and leave it in a station whilst other trains happen. Then, when you bring the train back, you can release it. It is all very simple to operate. Plus, being run through a web interface, I can run it on a tablet by the railway rather than having to lug a laptop around.

To back this up, there is a database that contains information about all the locos and wagons plus a list of possible trains. Using a bunch of random generators (RGs), a possible train is created using a chosen lok and a number of wagons. Through the use of the RGs, the lok, the number of wagons and the chosen wagons all may change from run to run. Plus, as each train may have any of three destinations, there is a lot of variation as the list of trains is run through.

What does PVDB know then?

It has access to data about each Lok, wagon and train, plus it has an area in the DB to store created trains; i.e. those that are recorded. The original data was created as a series of comma seperated files created on a spreadsheet. These were read in, an object created for each item in the list and then each was saved into the DB.

Lok Data

Each lok has the following stored:
lokNumber - for display purposes
lokName - unique
nationality - to define which wagons or coaches are suitable - currently only German or Swiss are recorded.
usage - defines the type of train that this lok can be used on.
inUse - a flag to show if it is currently saved in a recorded train (and, thus, cannot be used for another train until released)
id - a numeric value that is used to define the image of the lok.
key - the data value that is used to access any item in the bucket. For loks, this is #lokName.

Wagon Data

Wagon data is as follows:
id - a numeric value that is used to define the image of the wagon. This is also used where multiple wagons of the same type are available - e.g. Swiss dumper wagons - there are 6 in the database. Each wagon carries a sticker underneath with its id printed thereon.
usage - defines the type of train that this wagon can be used on.
nationality - to define which wagons or coaches are suitable - currently only German or Swiss are recorded.
usage - defines the type of train that this wagon can be used on.
inUse - a flag to show if it is currently saved in a recorded train (and, thus, cannot be used for another train until released)
key - the data value that is used to access any item in the bucket. For wagons, this is #idString, i.e. a character representation of the id - 1 = '1' and so on.

Train Data

Train data is as follows:
train - unique identifier of train type
category- defines the type of train.
lokType - self explanatory
frequency - out of 1 - 10 - determines how often this train type is used (subject to random selection - see later)
maximum - out of 1 - 10 - determines the maximum number of wagons/coaches in the train
minimum - out of 1 - 10 - determines the minimum number of wagons/coaches in the train

Creating a train

When the program starts, it builds a list of 50 trains. It takes the list of trains and using the frequency of each adds them to the list. Thus, each train type will appear multiple times subject to each trains frequency setting.The process for example, 2 would mean that for every set of trains, this one would appear twice and so on. With the current database, this results in a list of 54 trains with each type  spread randomly across the list.  Trains are processed in order. When the whole list has been used, a new set of trains will be built, with each type occurring in a different place in the list.


There are three destinations available for trains, depending on type, etc. These are Pennstadt, Hennersdorf and Valdorf. Coming out of the storage, trains can leave going left or right. If they go left, they have a choice of circulation and returning (Hennersdorf) or entering the station (Valdorf). If they take the right hand, they can only circulate (Pennstadt). The circulating trains will make a few circuits of the track and then return to the storage. Trains for Valdorf will enter the station. Passenger trains will have their locos released and placed on the outgoing end (or, if a cab coach train) just sit there until time to leave). Goods trains will be split up and processed into the goods shed, coal depot or oil depot as appropriate. Only trains with "local" or "Inter"  in their train type can have Valdorf as a destination.

Displaying a train

Each train will be displayed along with images of the wagons:

Managing Trains

As can be seen from the above screen shot, there are some options along the bottom of the screen:
Reload - create and display the next train without saving this one.
Save Train - This marks the train as persistent and saves it as a "Created Train". This means that the lok and wagons are reserved for this train and cannot be used for other trains. If the system tries to create another train which requires the same lok as this train, that new train will be skipped.
Save to Log - saves the train to the log file for debugging purposes
Cancel Train - discards the train and returns to the main menu.

Managing Created Trains

Once a train has been created; i.e. saved, the lok and wagons cannot be reused until the train is deleted.  Going to the Show Created Trains option on the main menu gives a list of current saved trains. Should one of these have been returned to storage, it can be reset which deletes the train and releases the lok and wagons back into the pool.
There are circumstances when you may wish to release just some of the wagons and lok. If, for instance, there is a local goods in Valdorf station, the lok might return to storage with only some of the wagons, leaving others in the goods yard. Under these circumstances, only the lok and the returned wagons need be released. When the next local goods comes it, it may return with these other wagons, in which case they can now be marked as returned. 
If the situation gets a bit complicated, there is a reset button that will clear everything out.

How does it all work in reality

It actually works very well. It is uncomplicated, fast and easy to use. It is almost bug free (just one that I know about). What it does is make the running of trains subject to a proper random process. Without it, I find that I run the trains that are on the layout and never swap them out. Too lazy, I guess. Using the program forces me to run different trains and to stick to the three destination protocol. There are two current issues that make it not quite great. My local passenger train lok is going back to Marklin to be fixed and I, currently, don't have any lok to run the local goods train service. My budget has run out but it will sort itself out in December when I have some software consultancy money coming from the USA. Let's hope that the pound tanks by then (that's the currency trader in me speaking!).

No comments: