Running
[Agent practical 10 of 9]


This final, extra, set of info is an special treat for those who are feeling especially dedicated. It will walk you through adding keyboard events to the model as an example of adding user interactions. At the same time, we'll talk a little about "threads"; a way of separating off processing into discrete areas of computing activity.


Here's our code, as it stands at the moment, with full(ish) comments etc., plus the parallelisation elements:

You might think that adding user interactions is just a matter of adding in a standard AWT listener, and, to an extent, it is. However, unlike a standard windows application which sits and waits for a user, when our model is running it is continually generating all kinds of events itself, chiefly events to repaint the model results. This causes considerable complications as we need to squeeze our user events into this sequence of internally-generated events.


Because interacting with the stuff on the screen is ultimately handled by the operating system, Java keeps calls associated with the GUI separated off from the rest of what it is doing in a "thread". Threads are quasi-independent chunks of processing that do their own thing unless told otherwise. They run through doing their processing jobs separate from the rest of the program. One advantage of threads is that they don't have to run at the same speed as the rest of the code. For example, if the operating system wants to temporarily suspend redrawing the screen, it can do so by halting the thread associated with GUI calls without halting the rest of the program. As it happens, the main program also runs in its own thread, called the 'main thread', though we haven't needed to know that so far.

The other main advantage with threads is that they can be allocated to other computing resources, for example a different core. We could, for example, allocate each agent a separate thread. This is a fairly common model for agent system, but complicates interaction a bit so we're not going to do this now. If you want an example, you can find such a framework used for RoboCode, a nice little tank-based ABM designed by IBM to help beginners practice Java.

Java allocates all AWT drawing-update requests to a special thread called the event dispatching thread (EDT). The EDT deals with all AWT events, which it treats like a queue of events to act upon*. Because so much repainting goes on, this queue is largely repainting update requests, like those continually made by our model to display the results, however it also includes user interaction events.

If we run our agents from our menu listening method, they'll be running in this thread as they'll be initiated from a single GUI event. Provided we're not trying to do anything else, this is fine, the agents run from this single event, albeit then adding GUI updates to the queue which occur when they can. However, the trouble comes when we want to interact with the agents and see the results on screen. At this point we're going to need to interleave the agents running with potential user-generated events. Adding a single "run this model" event to the EDT isn't going to work. Indeed, if we try to interact with our model using additional GUI listeners, all that happens is the "run this model" request is dealt with, and *then* the additional interactions in the order they happened. What the user sees is all the programmed agent movements, and then the user-led movements all at once at the end.

While there are a wide variety of (sometimes quite complicated) ways of dealing with this issue, the way we're going to do it is to start our model run from a new, additional, thread made inside our "Run Model" event listener. This thread, independent of the EDT, will then add events to the EDT when it needs to, generating multiple "model running" events in the queue, rather than just one. This gives the system the chance to deal with other user events between these.


Let's start by looking at how we code up the user interaction listener.


*Caveat lector: while the explanation given here for the EDT and how we get it working for this model kinda holds together, it's largely pulled together by *a lot* of experimentation. Most documentation for the EDT revolves around more complex multi-threaded applications, where the events generated are not of the default AWT types. In these circumstances you should consider shifting to Swing, which has a set of helper classes for dealing with event dispatching, and getting your head around events at a low level. A good starting point is Endre Stølsvik's writeup.