Check out the new USENIX Web site. next up previous
Next: The Implementation of JavaTriveni Up: Triveni: Design and Implementation Previous: Communication

   
The Triveni program for Battle

Figure 5 shows a three-player Battle game, and Figure 6 shows the architecture of a Battle player.


  
Figure 5: A three-player Battle game illustrating event-label renaming
\begin{figure}\setlength{\unitlength}{0.00066300in} %
\begingroup \makeatletter\...
...x(0,0)[b]{\smash{\SetFigFont{7}{8.4}{it}Player$_3$ }}}
\end{picture}\end{figure}

The ``wiring'' in these figures represents the various kinds of events of the system: the tokens attached to the wires are event labels, and the event data fields, if any, are shown inside parentheses. A wire that has different names at each end represents an explicit event-label renaming. For example, Figure 5 shows that to connect several players in a game, player i's generic event labels (e.g., Fire, Hit, etc.) are renamed to their corresponding event labels subscripted by i.

In the entire code for the Battle game, there is no explicit wiring for events. Instead, all events are broadcast throughout a parallel composition, and the Triveni constructs of event-label matching and scoping via LOCAL and RENAME provide the necessary ``wiring'' of event delivery.


  
Figure 6: Architecture of a Battle player
\begin{figure}\setlength{\unitlength}{0.00076300in} %
\begingroup \makeatletter\...
...x(0,0)[rb]{\smash{\SetFigFont{7}{8.4}{sf}Sunk(stat)}}}
\end{picture}\end{figure}

There are four kinds of GUI components for each player, shown as ovals in Figure 6.

The user-interface components are ``generic'' although they are not parameterized by a player index. Through event-label renaming, Triveni allows the differentiation and connection of multiple instances of a generic component. Indeed, user-interface components such as Player Window are most naturally implemented as subclasses of Activity embedded in and controlled by suitable subclasses of ActivityExpr:

  class PlayerWindowUI extends Activity {
   //...create the user interface for the player window
  }

  class PlayerWindow extends ActivityExpr {
    PlayerWindow {
      super(PlayerWindowUI); // embed the user interface 
                             // within this Expr
  }}
Player i is implemented as a parallel composition of the top-level components shown in Figure 6. Its pseudo-code realization in Triveni is shown below. To aid readability, we use the Triveni combinators in infix form rather than the implicit prefix form of section 3.2; for example, we use DO .. WATCHING .. instead of DoWatching(.., ..), A || B for Parallel(A,B), etc.

  class Player extends Expr {
   Player(i) {
    Expr e = RENAME[Fire_i/Fire, Hit_i/Hit, Sunk_i/Sunk, 
              Shield_i/Shield, Unshield_i/Unshield, 
              Abort_i/Abort] IN
                DO
                    AbortButton
                 || Shield(number, duration)
                 || SUSPEND Shield [PlayerOcean]
                    RESUME Unshield               
                 || OpponentOcean(1) || ... 
                 || OpponentOcean(n)    // except i
                WATCHING Abort;
    become(e);   
  }}

This code performs the renaming shown in Figure 5. The whole process is wrapped inside a DO-WATCHING construct, which preemptively terminates player i upon receipt of an Abort event. This is indicated in Figure 6 as a small boxed X at the scope of the entire player. Since the GUI components of the system are implemented as Activities, they are fully controlled by their surrounding ActivityExprs. Therefore, when a player presses the abort button, the single DO-WATCHING construct above terminates each component of his/her GUI. The SUSPEND-RESUME construct is used to ensure that when a player raises a shield, his/her own ocean is suspended until the shield runs out. While it is suspended, it will not respond to Fire events, but the player may still fire upon opponent oceans.

The player's shield process has an auxiliary timer Activity embedded in a subclass of ActivityExpr. This timer process will be reused throughout this example.

  class Timer extends ActivityExpr {
    Timer(duration) {
      // accepts: Start
      // emits:   Finish
  }}

The implementation of a timer is not shown; it is a generic timer that is tied to the shield button via the event-label renaming given below. The shield process comprises three components running in parallel:

1.
The shield button, which is terminated upon receipt of an OutOfShields event.

2.
A loop that decrements an instance variable numshields every time a shield is raised and emits an OutOfShields event when numshields reaches 0.

3.
The shield timer.

The pseudo-code for the Shield process is as follows:

  class Shield extends Expr {
   int numshields;
   Shield(number, duration) {
    numshields = number;
    Expr e = LOCAL OutOfShields IN
                 DO ShieldButton WATCHING OutOfShields
              || LOOP Shield -> { numshields--; } 
                                  SWITCH (numshields == 0)
                                  true: EMIT OutOfShields
                                  false: DONE
              || LOOP 
                  RENAME [Shield/Start, Unshield/Finish] 
                  IN Timer(duration);
    become(e);
  }}

The LOCAL hides the OutOfShields event from the rest of the system.

A player's ocean is parameterized by k ship processes, and is a parallel composition of all of them along with the player's window.

  class PlayerOcean extends Expr {
    PlayerOcean(ship1, ..., shipk) {
      Expr e = LOCAL ShipUIEvent_1, ..., ShipUIEvent_k IN
                   PlayerWindow
                || RENAME[ShipUIEvent_1/ShipUIEvent] IN ship1
                       ...
                || RENAME[ShipUIEvent_k/ShipUIEvent] IN shipk;
       become(e);
}}

The code above is set up in terms of Ships and ShipUIEvents and exploits the inheritance hierarchy on Triveni objects and events, as illustrated in Figure 3. Thus, each one can be a battleship or a submarine.

Each ship is parameterized by a ShipStatus object that specifies its dimensions, position, and damage. When a ship process is started, it emits its status; these events are handled by the player window. Then (via the SEQ construct), it enters an event loop that reacts to Fire events, each carrying position data. The update method updates status upon a hit.

  class Ship extends Expr {
    ShipStatus status;
    Ship(initial_status) {
      status = initial_status;
      Expr e = DO
                 EMIT Status(status)
                 SEQ 
                 LOOP Fire(pos) -> SWITCH(status.update(pos))
                                     Hit: EMIT Hit(pos)
                                    Sunk: EMIT Sunk(status)
                                    Miss: DONE
               WATCHING Sunk;
      become(e);
  }}

Battleships and submarines are implemented as subclasses of ship as illustrated in Figure 3, and share the above collision-control behavior.

A battleship contains two new instance variables, dir and speed, and adds a process in parallel with a generic ship process to handle Move events. At any point in time, a battleship is either stationary (speed is 0) or mobile. In the stationary state, it is awaiting an appropriate Move event to trigger a local Mobile event. In the mobile state, it invokes the move method of status at intervals of 1/speed until it becomes stationary again. Both the battleship and submarine processes reuse the timer process, originally introduced for the shield process above.

  class Battleship extends Ship {
    Direction dir;
    int speed;
    Battleship(initial_status) {
      super(initial_status);
      Expr e = DO
                   this    // behavior inherited from Ship
                || LOCAL Stationary,Mobile,Start,Finish IN
                           LOOP Move(d,s) -> 
                                  { dir = d; speed = s; }
                                  SWITCH (speed == 0)
                                     true: EMIT Stationary
                                    false: EMIT Mobile
                        || LOOP 
                             DO
                               AWAIT Mobile ->
                                   LOOP 
                                     EMIT Start
                                     SEQ
                                     AWAIT Finish -> 
                                       {status.move(dir)} 
                                       EMIT Status(status)
                                || 
                                   LOOP Timer(1/speed)
                             WATCHING Stationary
               WATCHING Sunk;
      become(e);
  }}

A submarine is a ship that is suspended upon receipt of a Dive event and resumed after some duration of time. Suspending a ship suspends the collision-control process and thus renders it invulnerable to attack.

  class Submarine extends Ship {
    Submarine(initial_status, dive_duration) {
      super(initial_status);
      Expr e = DO LOCAL Start, Finish IN
                       SUSPEND Start [this] 
                       RESUME Finish
                    || LOOP Dive -> ( EMIT Start 
                                      SEQ 
                                      AWAIT Finish )
                    || LOOP Timer(dive_duration)
               WATCHING Sunk;
      become(e);
  }}

An opponent ocean is an opponent window, with the events appropriately renamed to tie together with the opponent's process in a multiplayer game. If an opponent aborts the game, this will cause his/her corresponding ocean on the screens of all other players to disappear. Since Shield and Unshield events are broadcast each player knows when an opponent has raised a shield.

  class OpponentOcean extends Expr {
    OpponentOcean(j) {
      Expr e = RENAME [Fire_j/Fire, Hit_j/Hit, Sunk_j/Sunk, 
                       Shield_j/Shield, Unshield_j/Unshield, 
                       Abort_j/Abort] IN
               DO OpponentWindow WATCHING Abort;
      become(e);
  }}

An n-player game is simply constructed by composing n player processes in parallel.


next up previous
Next: The Implementation of JavaTriveni Up: Triveni: Design and Implementation Previous: Communication
1998-03-16