home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / applets / nuclear / nuclearp.jav < prev    next >
Encoding:
Text File  |  1995-10-12  |  50.6 KB  |  1,381 lines

  1.  
  2. import java.awt.Image;
  3. import java.awt.image.ImageObserver;
  4. import java.awt.Graphics;
  5. import java.awt.Color;
  6. import java.awt.Button;
  7. import java.awt.Dimension;
  8. import java.awt.Container;
  9. import java.awt.Window;
  10. import java.awt.Panel;
  11. import java.awt.BorderLayout;
  12. import java.awt.FlowLayout;
  13. import java.awt.Event;
  14.  
  15. import java.net.URL;
  16. import java.io.DataInputStream;
  17. import java.io.DataOutputStream;
  18. import java.util.StringTokenizer;
  19.  
  20. /* Copyright (C) 1995 Linkoping University, Linkoping, Sweden. */
  21.  
  22. /**
  23.  * The class NuclearPlant is an applet that lets you run a nuclear power plant
  24.  *
  25.  * @version 1.0f
  26.  * @author Henrik Eriksson
  27.  */
  28.           public class NuclearPlant extends java.applet.Applet implements Runnable {
  29.  
  30.               /** The thread that updates the display (for animation) */
  31.               protected Thread kicker = null;
  32.  
  33.               /** The thread that runs the sequences */
  34.               protected Thread buttonThread;
  35.  
  36.               /** The amount of time too sleep between display updates (ms?) */
  37.               protected int kickerDelay;
  38.  
  39.               /** The offscreen image */
  40.               protected Image im;
  41.  
  42.               /** The offscreen graphics context */
  43.               protected Graphics offscreen;
  44.  
  45.               /** The static background image */
  46.               protected Image background;
  47.  
  48.               /** The directory that contains the images. This
  49.                   directory is the location for GIFS for the
  50.                   background, plant components, and display
  51.                   animation. */
  52.               static String imageDir = "images/";
  53.  
  54.               /** The reactor object */
  55.               Reactor reactor;
  56.  
  57.               /** Valve object */
  58.               Valve valve_1, valve_2, valve_3, valve_4;
  59.  
  60.               /** Pump object */
  61.               Pump pump_1, pump_2, pump_3;
  62.  
  63.               /** The turbine */
  64.               Turbine turbine;
  65.  
  66.               /** The condenser */
  67.               Condenser condenser;
  68.  
  69.               /** The generator */
  70.               Generator generator;
  71.  
  72.               /** The nuclear power plant simulator */
  73.               Simulator simulator;
  74.  
  75.               /** Panel for the sequence control buttons */
  76.               Panel controlPanel, sequencePanel;
  77.  
  78.               Stop_Button stopButton;
  79.  
  80.               /** Flag that is true iff a simulation is running */
  81.               boolean isRunningSimulation = false;
  82.  
  83.               /** The status message that is display in the applet area */
  84.               String message = " ";
  85.  
  86.               /** Initialize the applet. Sets the applet size, creates
  87.                   the plant components, and creates the simulator. */
  88.               public void init() {
  89.                   //resize(680, 473);       // java.applet.Applet size
  90.                   im = createImage(680,473);
  91.                   offscreen = im.getGraphics();
  92.                   offscreen.setColor(Color.black);
  93.  
  94.                   background = getImage(getCodeBase(), imageDir + "BACKGROUND.GIF");
  95.  
  96.                   Component.plant = this;
  97.                   reactor = new Reactor();
  98.                   valve_1 = new Valve("SV1", 360, 59);
  99.                   valve_2 = new Valve("SV2", 360, 178);
  100.                   valve_3 = new Valve("WV1", 385, 382);
  101.                   valve_4 = new Valve("WV2", 385, 420);
  102.                   pump_1 = new Pump("Pump 1", 406, 389, 1400);
  103.                   pump_2 = new Pump("Pump 2", 406, 427, 1400);
  104.                   pump_3 = new Pump("Pump 3", 619, 421, 1285);
  105.                   turbine = new Turbine();
  106.                   condenser = new Condenser();
  107.                   generator = new Generator();
  108.  
  109.           setLayout(new BorderLayout());
  110.  
  111.           sequencePanel = new Panel();
  112.           sequencePanel.setLayout(new FlowLayout());
  113.                   sequencePanel.add(new Seq_1_Button(this, "Sequence 1"));
  114.                   sequencePanel.add(new Seq_2_Button(this, "Sequence 2"));
  115.                   sequencePanel.add(new Seq_3_Button(this, "Sequence 3"));
  116.                   sequencePanel.add(new Rand_Button(this, "Randomize"));
  117.           controlPanel = new Panel();
  118.           controlPanel.setLayout(new FlowLayout());
  119.                   controlPanel.add(sequencePanel);
  120.                   stopButton = new Stop_Button(this, "STOP");
  121.                   stopButton.disable();
  122.                   controlPanel.add(stopButton);
  123.           add("North", controlPanel);
  124.  
  125.           simulator = new LocalSimulator(this);
  126.               }
  127.  
  128.  
  129.               /** Update the plant display
  130.                 * @param g Graphics context to paint in */
  131.               public void paint(Graphics g) {
  132.           if (reactor == null) {
  133.               return;
  134.           }
  135.                   if (!reactor.overheated) {
  136.             Dimension d = size();
  137.             offscreen.setColor(getBackground());
  138.             offscreen.fillRect(0, 0, d.width, d.height);
  139.  
  140.                     offscreen.drawImage(background,0,50, this);
  141.                     reactor.paint(offscreen);
  142.                     valve_1.paint(offscreen);
  143.                     valve_2.paint(offscreen);
  144.                     valve_3.paint(offscreen);
  145.                     valve_4.paint(offscreen);
  146.                     pump_1.paint(offscreen);
  147.                     pump_2.paint(offscreen);
  148.                     pump_3.paint(offscreen);
  149.                     turbine.paint(offscreen);
  150.                     condenser.paint(offscreen);
  151.                     generator.paint(offscreen);
  152.                     offscreen.drawString(message, 50, 440);
  153.                   } else reactor.paintMeltdown(offscreen);
  154.                   g.drawImage(im,0,0, this);
  155.               }
  156.  
  157.  
  158.               /** Update without erasing background
  159.                 * @param g Graphics context to update in */
  160.               public void update(Graphics g) {
  161.                 paint(g);
  162.               }
  163.  
  164.               /** Handle mouseDown events. This method distributes the
  165.                   message by calling the mouseDown methods for the
  166.                   appropriate plant components
  167.                 * @param x The X coordinate
  168.                 * @param y The Y coordinate */
  169.               public boolean mouseDown(Event evt, int x, int y) {
  170. // getAppletContext().showStatus("mouseDown " + x + " " + y);
  171.                 if (isRunningSimulation) {
  172.                   if (simulator instanceof LocalSimulator) {
  173.                     pump_1.mouseDown(evt, x, y);
  174.                     pump_2.mouseDown(evt, x, y);
  175.                     pump_3.mouseDown(evt, x, y);
  176.                     valve_1.mouseDown(evt, x, y);
  177.                     valve_2.mouseDown(evt, x, y);
  178.                     valve_3.mouseDown(evt, x, y);
  179.                     valve_4.mouseDown(evt, x, y);
  180.                     reactor.mouseDown(evt, x, y);
  181.                   }
  182.                 } else getAppletContext().showStatus("Start the simulation by clicking on a sequence button");
  183.         return true;
  184.               }
  185.  
  186.  
  187.               /** Handle mouseDrag events. This method distributes the
  188.                   message by calling the mouseDrag methods for the
  189.                   appropriate plant components
  190.                 * @param x The X coordinate
  191.                 * @param y The Y coordinate */
  192.               public boolean mouseDrag(Event evt, int x, int y) {
  193.                 return reactor.mouseDrag(evt, x, y);
  194.               }
  195.  
  196.               /** Handle mouseUp events. This method distributes the
  197.                   message by calling the mouseUp methods for the
  198.                   appropriate plant components
  199.                 * @param x The X coordinate
  200.                 * @param y The Y coordinate */
  201.               public boolean mouseUp(Event evt, int x, int y) {
  202.                 return reactor.mouseUp(evt, x, y);
  203.               }
  204.  
  205.               /** Rotate the pumps one step. (Only pumps with rpm > 0
  206.                   are rotated.) */
  207.               protected void rotatePumps() {
  208.                 pump_1.rotate();
  209.                 pump_2.rotate();
  210.                 pump_3.rotate();
  211.               }
  212.  
  213.               /** Move the waves on the water surfaces in the tanks */
  214.               protected void waterWave() {
  215.                 reactor.waterWave();
  216.                 condenser.waterWave();
  217.               }
  218.  
  219.               /** Start the simulation */
  220.               public void startReactor() {
  221.                   getAppletContext().showStatus("The simulation is running...");
  222.                   simulator.start();
  223.               }
  224.  
  225.               /** Run the simulation n steps. Uses the crurrent
  226.                 * simulator to calculate the next states
  227.                 * @param n The number of steps */
  228.               public void timeStep(int n) {
  229.                   simulator.timeStep(n);
  230.               }
  231.  
  232.               /** Blow up a device.
  233.                 * @param device The device to blow (e.g., a turbine object) */
  234.               public void blow(Component device) {
  235.                   simulator.blow(device);
  236.               }
  237.  
  238.               /** Stop the simulation */
  239.               public void stopReactor() {
  240.                   getAppletContext().showStatus("The simulation has stopped");
  241.                   simulator.stop();
  242.               }
  243.  
  244.               /** Play a crash sound. This method is called when plant
  245.                   components blow up.
  246.                 * @param n Duration */
  247.               public void crashSound(int n) {
  248.                 if (n < 1000)
  249.                   play(getCodeBase(), "audio/breakdown.au");
  250.                 else if (n < 10000)
  251.                   play(getCodeBase(), "audio/Explosion-2.au");
  252.                 else
  253.                   play(getCodeBase(), "audio/Explosion-1.au");
  254.               }
  255.  
  256.  
  257.               /** Run the animation thread. This method is called when
  258.                   the animation thread is started. */
  259.               public void run() {
  260.                 Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
  261.                 while (kicker != null) {
  262.                   if (isRunningSimulation) {
  263.                     rotatePumps();
  264.                     waterWave();
  265.                   }
  266.                   repaint();
  267. try {Thread.sleep(kickerDelay);} catch (InterruptedException e){}
  268.                 }
  269.               }
  270.  
  271.               /** Start the applet. Creates the animation thread */
  272.               public void start() {
  273.                 if (kicker == null) {
  274.                   kicker = new Thread(this);
  275.                   kickerDelay = 60;
  276.                   kicker.start();
  277.                 }
  278.               }
  279.  
  280.               /** Stop the applet. Stops the animation thread and
  281.                   closes the window for the sequence control buttons */
  282.               public void stop() {
  283.                 if (kicker != null) {
  284.                   kicker.stop();
  285.                   kicker = null;
  286.                 }
  287.               }
  288.           }
  289.  
  290.  
  291. /**
  292.  * The class SeqButton is an abstract class for buttons that control
  293.  * simulation sequences.
  294.  *
  295.  * @version 1.0f
  296.  * @author Henrik Eriksson
  297.  */
  298.           abstract class SeqButton extends Button implements Runnable {
  299.               /** Backpointer to the NuclearPlant applet */
  300.               protected NuclearPlant plant;
  301.  
  302.               /** Construct a button and initialize it.
  303.                 * @param p The plant
  304.                 * @param name The button label */
  305.               public SeqButton(NuclearPlant p, String name) {
  306.                 super(name);
  307.                 plant = p;
  308.               }
  309.  
  310.               /** Perform a sequence when the button is selected. This
  311.                   method is called automatically when the button is
  312.                   selected by the user. The method runs the sequence
  313.                   in a separate thread.
  314.                 * @param evt the Event
  315.                 * @param arg the argument */
  316.               public boolean action(Event evt, Object arg) {
  317.                 plant.buttonThread = new Thread(this);
  318.                 plant.buttonThread.start();
  319.         return true;
  320.               }
  321.  
  322.           }
  323.  
  324.  
  325. /**
  326.  * Class for the Sequence 1 button.
  327.  *
  328.  * @version 1.0f
  329.  * @author Henrik Eriksson
  330.  */
  331.           class Seq_1_Button extends SeqButton {
  332.               /** Construct a button and initialize it.
  333.                 * @param p The plant
  334.                 * @param name The button label
  335.                 * @param x The X coordinate
  336.                 * @param y The Y coordinate */
  337.               public Seq_1_Button(NuclearPlant p, String name) {
  338.                 super(p, name);
  339.               }
  340.  
  341.               /** Run the sequence. This method is called in a
  342.                   separate thread when the button is selected by the
  343.                   user. Modify this method to change the sequence in
  344.                   question. */
  345.               public void run() {
  346.         plant.sequencePanel.disable();
  347.         plant.stopButton.enable();
  348.         plant.isRunningSimulation = true;
  349.                 plant.startReactor();
  350.                 plant.message = "Sequence 1 running...";
  351.                 plant.timeStep(25);
  352.                 plant.blow(plant.turbine);
  353.                 plant.timeStep(200);
  354.                 plant.message = " ";
  355.                 plant.stopReactor();
  356.         plant.isRunningSimulation = false;
  357.         plant.sequencePanel.enable();
  358.         plant.stopButton.disable();
  359.               }
  360.  
  361.           }
  362.  
  363.  
  364. /**
  365.  * Class for the Sequence 2 button.
  366.  *
  367.  * @version 1.0f
  368.  * @author Henrik Eriksson
  369.  */
  370.           class Seq_2_Button extends SeqButton {
  371.               /** Construct a button and initialize it.
  372.                 * @param p The plant
  373.                 * @param name The button label
  374.                 * @param x The X coordinate
  375.                 * @param y The Y coordinate */
  376.               public Seq_2_Button(NuclearPlant p, String name) {
  377.                 super(p, name);
  378.               }
  379.  
  380.               /** Run the sequence. This method is called in a
  381.                   separate thread when the button is selected by the
  382.                   user. Modify this method to change the sequence in
  383.                   question. */
  384.               public void run() {
  385.         plant.sequencePanel.disable();
  386.         plant.stopButton.enable();
  387.                 plant.startReactor();
  388.         plant.isRunningSimulation = true;
  389.                 plant.message = "Sequence 2 running...";
  390.                 plant.timeStep(25);
  391.                 plant.blow(plant.pump_1);
  392.                 plant.timeStep(140);
  393.                 plant.message = " ";
  394.                 plant.stopReactor();
  395.         plant.isRunningSimulation = false;
  396.         plant.sequencePanel.enable();
  397.         plant.stopButton.disable();
  398.               }
  399.           }
  400.  
  401.  
  402. /**
  403.  * Class for the Sequence 3 button.
  404.  *
  405.  * @version 1.0f
  406.  * @author Henrik Eriksson
  407.  */
  408.           class Seq_3_Button extends SeqButton {
  409.               /** Construct a button and initialize it.
  410.                 * @param p The plant
  411.                 * @param name The button label
  412.                 * @param x The X coordinate
  413.                 * @param y The Y coordinate */
  414.               public Seq_3_Button(NuclearPlant p, String name) {
  415.                 super(p, name);
  416.               }
  417.  
  418.               /** Run the sequence. This method is called in a
  419.                   separate thread when the button is selected by the
  420.                   user. Modify this method to change the sequence in
  421.                   question. */
  422.               public void run() {
  423.         plant.sequencePanel.disable();
  424.         plant.stopButton.enable();
  425.                 plant.startReactor();
  426.         plant.isRunningSimulation = true;
  427.                 plant.message = "Sequence 3 running...";
  428.                 plant.timeStep(25);
  429.                 plant.blow(plant.pump_3);
  430.                 plant.timeStep(200);
  431.                 plant.message = " ";
  432.                 plant.stopReactor();
  433.         plant.isRunningSimulation = false;
  434.         plant.sequencePanel.enable();
  435.         plant.stopButton.disable();
  436.               }
  437.           }
  438.  
  439.  
  440. /**
  441.  * Class for the random sequence button.
  442.  *
  443.  * @version 1.0f
  444.  * @author Henrik Eriksson
  445.  */
  446.           class Rand_Button extends SeqButton {
  447.               /** Construct a button and initialize it.
  448.                 * @param p The plant
  449.                 * @param name The button label
  450.                 * @param x The X coordinate
  451.                 * @param y The Y coordinate */
  452.               public Rand_Button(NuclearPlant p, String name) {
  453.                 super(p, name);
  454.               }
  455.  
  456.               /** Run the sequence. This method is called in a
  457.                   separate thread when the button is selected by the
  458.                   user. Modify this method to change the sequence in
  459.                   question. */
  460.               public void run() {
  461.         plant.sequencePanel.disable();
  462.         plant.stopButton.enable();
  463.                 plant.startReactor();
  464.         plant.isRunningSimulation = true;
  465.                 plant.message = "Random sequence running...";
  466.                 plant.timeStep(25);
  467.                 switch ((int)(Math.random()*5)) {
  468.                   case 0: plant.blow(plant.turbine); break;
  469.                   case 1: plant.blow(plant.pump_1); break;
  470.                   case 2: plant.blow(plant.pump_3); break;
  471.                   case 3: plant.blow(plant.condenser); break;
  472.                   case 4: plant.blow(plant.reactor); break;
  473.                 }
  474.                 plant.timeStep(25);
  475.                 switch ((int)(Math.random()*5)) {
  476.                   case 0: plant.blow(plant.turbine); break;
  477.                   case 1: plant.blow(plant.pump_1); break;
  478.                   case 2: plant.blow(plant.pump_3); break;
  479.                   case 3: plant.blow(plant.condenser); break;
  480.                   case 4: plant.blow(plant.reactor); break;
  481.                 }
  482.                 plant.timeStep(140);
  483.                 plant.message = " ";
  484.                 plant.stopReactor();
  485.         plant.isRunningSimulation = false;
  486.         plant.sequencePanel.enable();
  487.         plant.stopButton.disable();
  488.               }
  489.           }
  490.  
  491.  
  492. /**
  493.  * Class for the stop button.
  494.  *
  495.  * @version 1.0f
  496.  * @author Henrik Eriksson
  497.  */
  498.           class Stop_Button extends Button {
  499.  
  500.               /** Backpointer to the NuclearPlant applet */
  501.               protected NuclearPlant plant;
  502.  
  503.               /** Construct a button and initialize it.
  504.                 * @param p The plant
  505.                 * @param name The button label */
  506.               public Stop_Button(NuclearPlant p, String name) {
  507.                 super(name);
  508.                 plant = p;
  509.               }
  510.  
  511.               /** Stop a running the sequence. Modify this method to change
  512.                   the stop function.
  513.                 * @param evt the Event
  514.                 * @param arg the argument */
  515.               public boolean action(Event evt, Object arg) {
  516.         plant.isRunningSimulation = true;
  517.                 plant.buttonThread.stop();
  518.                 plant.stopReactor();
  519.                 plant.message = " ";
  520.         plant.isRunningSimulation = false;
  521.         disable();
  522.         plant.sequencePanel.enable();
  523.         return true;
  524.               }
  525.           }
  526.  
  527.  
  528. /**
  529.  * Class for components of the nuclear power plant
  530.  *
  531.  * @version 1.0f
  532.  * @author Henrik Eriksson
  533.  */
  534.           class Component {
  535.               /** Backpointer to the plant */
  536.               protected static NuclearPlant plant;
  537.  
  538.               /** Component location */
  539.               protected int x, y;
  540.  
  541.               /** Component label (if any) */
  542.               protected String label;
  543.  
  544.               /** True iff component broken */
  545.               boolean blown = false;
  546.  
  547.               /** Returns an image given its name
  548.                 * @param name The image name 
  549.                 * @return The image */
  550.               protected final Image getImage(String name) {
  551.                 Image im = plant.getImage(plant.getCodeBase(), plant.imageDir + name);
  552.                 im.getWidth(plant);  // Initiate image fetching
  553.                 return im;
  554.               }
  555.  
  556.               /** Returns an image given its name
  557.                 * @param name The image name 
  558.                 * @param cache The image cache
  559.                 * @return The image */
  560.               protected final Image getImage(String name, Image cache) {
  561.                 if (cache instanceof Image) return cache;
  562.                 else return getImage(name);
  563.               }
  564.  
  565.  
  566.               /** No-op at this level */
  567.               void blow() {}
  568.  
  569.               /** Set the value of a slot (no-op at this level)
  570.                 * @param slot The slot name
  571.                 * @param val The value */
  572.               void setIntValue(String slot, int val) { }
  573.  
  574.               /** Set the value of a slot (no-op at this level)
  575.                 * @param slot The slot name
  576.                 * @param val The value */
  577.               void setValue(String slot, float val) { }
  578.  
  579.               /** Set the value of a slot (no-op at this level)
  580.                 * @param slot The slot name
  581.                 * @param val The value */
  582.               void setValue(String slot, String val) { }
  583.  
  584.               /** Set the value of a slot
  585.                 * @param slot The slot name
  586.                 * @param val The value */
  587.               void setValue(String slot, boolean val) {
  588.                 if (slot.equals("blown")) blown = val;
  589.               }
  590.  
  591.               /** Random number generator (pseudo)
  592.                 * @param min The lower bound
  593.                 * @param max The upper bound
  594.                 * @return A random number (between min and max) */
  595.               protected final int rand(int min, int max) {
  596.                 return (int)(Math.random()*(max-min) + min);
  597.               }
  598.  
  599.           }
  600.  
  601. /**
  602.  * A generic tank component for the nuclear power plant
  603.  *
  604.  * @version 1.0f
  605.  * @author Henrik Eriksson
  606.  */
  607.           class Tank extends Component {
  608.  
  609.               /** The tank pressure (in bar) */
  610.               float pressure;
  611.  
  612.               /** The tank waterlevel (in mm) */
  613.               float waterLevel;
  614.  
  615.               /** The number of the water image shown */
  616.               protected int imageState = 0;
  617.  
  618.               /** Water (surface) images for animation */
  619.               protected static Image water_bm[];
  620.  
  621.               /** Blow up the tank */
  622.               void blow() {
  623.                 plant.crashSound(15000);
  624.                 plant.getAppletContext().showStatus("The " + label + " blow up");
  625.                 blown = true;
  626.               }
  627.  
  628.               /** Set the value of a slot
  629.                 * @param slot The slot name
  630.                 * @param val The value */
  631.               void setValue(String slot, float val) {
  632.                 if (slot.equals("pressure")) pressure = val;
  633.                 else if (slot.equals("waterLevel")) waterLevel = val;
  634.                 else super.setValue(slot, val);
  635.               }
  636.  
  637.               /** Array of bubble depths */
  638.               private int bubble_depth[] = new int[100];
  639.  
  640.               /** Array of bubble X positions */
  641.               private int bubble_x[] = new int[100];
  642.  
  643.               /** Paint animated bubbles in a region
  644.                 * @param g The graphics context
  645.                 * @param x The X position for the bubble region
  646.                 * @param y The Y position for the bubble region
  647.                 * @param size().width The size().width of the bubble region
  648.                 * @param size().height The size().height of the bubble region
  649.                 * @param noOfBubbles The bubble frequency */
  650.               protected final void paintBubbles(Graphics g, int x, int y,
  651.                                int width, int depth, int noOfBubbles) {
  652.                   if (plant.isRunningSimulation) {
  653.                     Color oldForeground = g.getColor();
  654.                     g.setColor(Color.white);
  655.                     if (noOfBubbles > bubble_depth.length)
  656.                       noOfBubbles = bubble_depth.length;
  657.                     for (int i=0; i < noOfBubbles; i++) {
  658.                       if (bubble_depth[i] == 0) {     // Create a new bubble
  659.                         bubble_depth[i] = rand(1, depth);
  660.                         bubble_x[i] = rand(x, width);
  661.                       }
  662.                       g.fillRect(bubble_x[i], y+bubble_depth[i]--, 1, 1);
  663. Thread.yield();
  664.                     }
  665.                     g.setColor(oldForeground);
  666.                   }
  667.               }
  668.           }
  669.  
  670.  
  671. /**
  672.  * A reactor tank component for the nuclear power plant
  673.  *
  674.  * @version 1.0f
  675.  * @author Henrik Eriksson
  676.  */
  677.           class Reactor extends Tank {
  678.  
  679.               /** The moderator rod level (in percent) */
  680.               int moderatorPercent = 50;
  681.  
  682.               /** True iff the reactor is overheated */
  683.               boolean overheated;
  684.  
  685.               /** The state of a meltdown */
  686.               private int meltStage;
  687.  
  688.               /** Water (surface) images for animation */
  689.               protected static Image water_bm[] = new Image[3];
  690.  
  691.               /** Image for a blown reactor tank */
  692.               protected static Image crashed_reactor_bm;
  693.  
  694.               /** Radiation sign (image) */
  695.               protected static Image radiak_bm;
  696.  
  697.               Reactor() {
  698.                   water_bm[0] = getImage("R_VATTEN_A_BM.GIF", water_bm[0]);
  699.                   water_bm[1] = getImage("R_VATTEN_B_BM.GIF", water_bm[1]);
  700.                   water_bm[2] = getImage("R_VATTEN_C_BM.GIF", water_bm[2]);
  701.                   crashed_reactor_bm =
  702.                         getImage("CRASHED_REACTOR_BM.GIF", crashed_reactor_bm);
  703.                   radiak_bm = getImage("RADIAK_BM.GIF", radiak_bm);
  704.                   label = "reactor";
  705.                   waterLevel = 1800;
  706.               }
  707.  
  708.               /** Set the value of a slot
  709.                 * @param slot The slot name
  710.                 * @param val The value */
  711.               void setIntValue(String slot, int val) {
  712.                 if (slot.equals("moderatorPercent")) moderatorPercent = val;
  713.                 else super.setIntValue(slot, val);
  714.               }
  715.  
  716.               /** Set the value of a slot
  717.                 * @param slot The slot name
  718.                 * @param val The value */
  719.               void setValue(String slot, boolean val) {
  720.                 if (slot.equals("overheated")) {
  721.                   overheated = val;
  722.                   if (val) meltdown();
  723.                 } else super.setValue(slot, val);
  724.               }
  725.  
  726.               /** Advance the water-surface animation one step */
  727.               void waterWave () {
  728.                 if (++imageState >= water_bm.length) imageState = 0;
  729.               }
  730.  
  731.               /** Perform the meltdown animation. Called when the reactor
  732.                   core is overheated */
  733.               public void meltdown() {
  734.                 overheated = true;
  735.                 plant.kickerDelay = 40;
  736.                 meltStage = 5;
  737.                 plant.getAppletContext().showStatus("The " + label + " is overheated");
  738.               }
  739.  
  740.               /** Paint operation for the meltdown animation
  741.                 * @param g The graphics context */
  742.               public void paintMeltdown(Graphics g) {
  743.  
  744.                 //im = new Image(item.parent);
  745.                 //offscreen = new Graphics(im);
  746.  
  747. //                int x0 = 10, y0 = 150;
  748.                 int x0 = -60, y0 = 110;
  749.                 if (meltStage == 5) g.drawImage(radiak_bm, 170, 150, plant);
  750.                 if (meltStage < 1500) {
  751.                   int d = meltStage;
  752.                   int x = Math.max(x0 - (d - 100), 0) +
  753.                           rand(0, Math.min(d, plant.size().width));
  754.                   int y = Math.max(y0 - (d - 100), 0) +
  755.                           rand(0, Math.min(d, plant.size().height));
  756.                   // BITBLT
  757.                   g.copyArea(x, y,
  758.                            rand(10, 100),
  759.                            rand(10, 100),
  760.                            ((d < 250) ? rand(-3, 3) : rand(-2, 2)),
  761.                            ((d < 250) ? rand(-3, 3) : rand(-2, 2)));
  762.                   meltStage++;
  763.                 }
  764.               }
  765.  
  766.  
  767.               /** The color of overheated fuel rods */
  768.               private static Color overheatedColor = new Color(200,0,0);
  769.  
  770.               /** The color of water */
  771.               private static Color waterColor = new Color(128,192,255);
  772.  
  773.  
  774.               /** Paint operation for the reactor tank
  775.                 * @param g The graphics context */
  776.               public void paint(Graphics g) {
  777.                   g.setColor(Color.black);
  778.                   if (pressure > 500) g.setColor(Color.red);
  779.                   g.drawString((int)pressure+" bar", 55, 70);
  780.                   int surfaceY = 175-(int)waterLevel/50;
  781.                   g.setColor(waterColor);
  782.                   g.fillRect(3, surfaceY+1, 135, 279-surfaceY);
  783.                   g.setColor(Color.black);
  784.                   g.drawImage(water_bm[imageState], 3, surfaceY, plant);
  785.                   g.drawString("Level:", 160, 110);
  786.                   if (waterLevel < 0) g.setColor(Color.red);
  787.                   g.drawString((int)waterLevel+" mm", 160, 125);
  788.                   g.setColor(Color.gray);
  789.                   for (int i = 0; i < 7; i++)
  790.                       g.fillRect(33 + i*12, 102+moderatorPercent*3/4, 3, 80);
  791.                   if (moderatorOutlinePos > 0) {
  792.                     g.setColor(Color.yellow);
  793.                     for (int i = 0; i < 7; i++)
  794.                       g.drawRect(33 + i*12, moderatorOutlinePos, 2, 80);
  795.                   }
  796.                   if (waterLevel < 0) {
  797.                     Color hotColor =
  798.                             new Color(Math.min(-(int)waterLevel/10,150),0,0);
  799.                     g.setColor(hotColor);
  800.                   } else g.setColor(Color.black);
  801.                   for (int i = 0; i < 8; i++)
  802.                       g.fillRect(25 + i*12, 177, 7, 80);
  803.                   if (waterLevel < 0) {
  804.                     g.setColor(overheatedColor);
  805.                     for (int i = 0; i < 8; i++)
  806.                         g.fillRect(25 + i*12, 177, 7,
  807.                              Math.max(-(int)waterLevel/50-1, 0));
  808.                   }
  809.                   g.setColor(Color.black);
  810.                   if (waterLevel > 0)
  811.                     paintBubbles(g, 3, surfaceY, 137, 50, 50);
  812.                   else
  813.                     paintBubbles(g, 3, surfaceY, 137, 60, 100);
  814.                   if (blown) {
  815.                     g.drawImage(crashed_reactor_bm, 30, 3, plant);
  816.                     g.drawImage(radiak_bm, 170, 150, plant);
  817.                   }
  818.               }
  819.  
  820.               /** Initial Y position for dragged moderator rods */
  821.               private int y0 = 0;
  822.  
  823.               /** The distance of the drag */
  824.               protected int dragDelta = 0;
  825.  
  826.               /** The position of the outline of the dragged moderator rods */
  827.               protected int moderatorOutlinePos = 0;
  828.  
  829.               /** Checks if a certain position is inside the area of
  830.                   the moderator rods
  831.                 * @param x The X coordinate
  832.                 * @param y The Y coordinate
  833.                 * @return True iff the position is inside the moderator-rod
  834.                           area, otherwise false */
  835.               private boolean isInsideModerator(int x, int y) {
  836.                 return x > 25 && x < 120 && y > 102+moderatorPercent*3/4 &&
  837.                        y < 102+moderatorPercent*3/4 + 80;
  838.               }
  839.  
  840.               /** Handle mouseDown events (i.e., clicks on moderator rods).
  841.                 * @param x The X coordinate
  842.                 * @param y The Y coordinate */
  843.               public boolean mouseDown(Event evt, int x, int y) {
  844.                 if (isInsideModerator(x, y)) {
  845.                   y0 = y;
  846.                 }
  847.         return true;
  848.               }
  849.  
  850.               /** Handle mouseDrag events. This method allows the user to
  851.                   drag moderator rods
  852.                 * @param x The X coordinate
  853.                 * @param y The Y coordinate */
  854.               public boolean mouseDrag(Event evt, int x, int y) {
  855.                 if (y0 > 0) {
  856.                   moderatorOutlinePos = 102+moderatorPercent*3/4 - (y0 - y);
  857.                   if (moderatorOutlinePos < 97) moderatorOutlinePos = 97;
  858.                   if (moderatorOutlinePos > 177) moderatorOutlinePos = 177;
  859.                 }
  860.         return true;
  861.               }
  862.  
  863.               /** Handle mouseUp events. This method sets the moderatorPercent
  864.                 * @param x The X coordinate
  865.                 * @param y The Y coordinate */
  866.               public boolean mouseUp(Event evt, int x, int y) {
  867.                 if (y0 > 0 && moderatorOutlinePos > 0) {
  868.                   moderatorPercent = (moderatorOutlinePos - 97) * 5/4;
  869.                 }
  870.                 moderatorOutlinePos = 0;
  871.                 y0 = 0;
  872.         return true;
  873.               }
  874.  
  875.  
  876.           }
  877.  
  878.  
  879. /**
  880.  * A valve component for the nuclear power plant
  881.  *
  882.  * @version 1.0f
  883.  * @author Henrik Eriksson
  884.  */
  885.           class Valve extends Component {
  886.  
  887.               /** True iff the valve is open */
  888.               boolean status = false;
  889.  
  890.               /** Valve image */
  891.               protected static Image ventil_o_bm, ventil_s_bm;
  892.  
  893.               /** Construct a valve and initialize it.
  894.                 * @param l The valve label
  895.                 * @param xPos The X coordinate
  896.                 * @param yPos The Y coordinate */
  897.               Valve(String l, int xPos, int yPos) {
  898.                   x = xPos;
  899.                   y = yPos;
  900.                   label = l;
  901.                   ventil_o_bm = getImage("VENTIL.O_BM.GIF", ventil_o_bm);
  902.                   ventil_s_bm = getImage("VENTIL.S_BM.GIF", ventil_s_bm);
  903.               }
  904.  
  905.               /** Set the value of a slot
  906.                 * @param slot The slot name
  907.                 * @param val The value */
  908.               void setValue(String slot, boolean val) {
  909.                 if (slot.equals("status")) status = val;
  910.                 else super.setValue(slot, val);
  911.               }
  912.  
  913.               /** Paint operation for valve
  914.                 * @param g The graphics context */
  915.               public void paint(Graphics g) {
  916.                   if (status)
  917.                      g.drawImage(ventil_o_bm, x, y, plant);
  918.                   else
  919.                      g.drawImage(ventil_s_bm, x, y+6, plant);
  920.                   g.drawString(label, x, y+40);
  921.               }
  922.  
  923.               /** Handle mouseDown events (i.e., clicks on the valve).
  924.                 * @param mx The X coordinate
  925.                 * @param my The Y coordinate */
  926.               public boolean mouseDown(Event evt, int mx, int my) {
  927.                 if (mx > x && mx < x+20 && my > y && my < y+40) {
  928.                   status = !status;
  929.                 }
  930.         return true;
  931.               }
  932.  
  933.           }
  934.  
  935.  
  936. /**
  937.  * A pump component for the nuclear power plant
  938.  *
  939.  * @version 1.0f
  940.  * @author Henrik Eriksson
  941.  */
  942.           class Pump extends Component {
  943.  
  944.               /** The state of the pump (0=crashed) */
  945.               int status = 1;
  946.  
  947.               /** The pump rpm */
  948.               int rpm;
  949.  
  950.               /** Maximum pump rpm */
  951.               int full_rpm;
  952.  
  953.               /** Pump images for amimation */
  954.               protected static Image pump_bm[] = new Image[6];
  955.  
  956.               /** Crashed pump image */
  957.               protected static Image pump_crash_bm;
  958.  
  959.  
  960.               /** Construct a pump and initialize it.
  961.                 * @param l The pump label
  962.                 * @param xPos The X coordinate
  963.                 * @param yPos The Y coordinate
  964.                 * @param maxRpm The maximum pump rpm */
  965.               Pump(String l, int xPos, int yPos, int maxRpm) {
  966.                   x = xPos;
  967.                   y = yPos;
  968.                   label = l;
  969.                   full_rpm = maxRpm;
  970.                   pump_bm[0] = getImage("PUMP.A_BM.GIF", pump_bm[0]);
  971.                   pump_bm[1] = getImage("PUMP.B_BM.GIF", pump_bm[1]);
  972.                   pump_bm[2] = getImage("PUMP.C_BM.GIF", pump_bm[2]);
  973.                   pump_bm[3] = getImage("PUMP.D_BM.GIF", pump_bm[3]);
  974.                   pump_bm[4] = getImage("PUMP.E_BM.GIF", pump_bm[4]);
  975.                   pump_bm[5] = getImage("PUMP.F_BM.GIF", pump_bm[5]);
  976.                   pump_crash_bm = getImage("PUMP.CRASH_BM.GIF", pump_crash_bm);
  977.               }
  978.  
  979.  
  980.               /** Set the value of a slot
  981.                 * @param slot The slot name
  982.                 * @param val The value */
  983.               void setIntValue(String slot, int val) {
  984.                 if (slot.equals("status")) status = val;
  985.                 else if (slot.equals("rpm")) rpm = val;
  986.                 else super.setIntValue(slot, val);
  987.               }
  988.  
  989.               /** Blow up the pump */
  990.               void blow() {
  991.                 plant.crashSound(800);
  992.                 plant.getAppletContext().showStatus(label + " crashed");
  993.                 status = 0;
  994.                 rpm = 0;
  995.               }
  996.  
  997.               /** Rotate the pump one step. (Only pumps with rpm > 0
  998.                   are rotated.) */
  999.               public void rotate() {
  1000.                 if (rpm > 0 && status != 0) status++;
  1001.                 if (status > 6) status = 1;
  1002.               }
  1003.  
  1004.               /** Paint operation for pump
  1005.                 * @param g The graphics context */
  1006.               public void paint(Graphics g) {
  1007.                   if (status == 0) g.drawImage(pump_crash_bm, x, y, plant);
  1008.                   else g.drawImage(pump_bm[status-1], x, y, plant);
  1009.                   g.drawString(rpm+" rpm", x+4, y-2);
  1010.               }
  1011.  
  1012.               /** Handle mouseDown events (i.e., clicks on the pump).
  1013.                 * @param mx The X coordinate
  1014.                 * @param my The Y coordinate */
  1015.               public boolean mouseDown(Event evt, int mx, int my) {
  1016.                 if (mx > x && mx < x+30 && my > y && my < y+30)
  1017.                   if (status != 0)
  1018.                     if (rpm == 0) rpm = full_rpm; else rpm = 0;
  1019.         return true;
  1020.               }
  1021.  
  1022.           }
  1023.  
  1024.  
  1025.  
  1026. /**
  1027.  * Turbine component for the nuclear power plant
  1028.  *
  1029.  * @version 1.0f
  1030.  * @author Henrik Eriksson
  1031.  */
  1032.           class Turbine extends Component {
  1033.  
  1034.               /** Image of crash turbine */
  1035.               protected static Image crashed_turbine_bm;
  1036.  
  1037.               /** Construct a turbine and initialize it. */
  1038.               Turbine() {
  1039.                 crashed_turbine_bm =
  1040.                       getImage("CRASHED_TURBIN_BM.GIF", crashed_turbine_bm);
  1041.               }
  1042.  
  1043.               /** Blow up the turbine */
  1044.               void blow() {
  1045.                   blown = true;
  1046.               }
  1047.  
  1048.               /** Count down for blow up animation */
  1049.               private byte blow_countdown = -1;
  1050.  
  1051.               /** Paint operation for turbine
  1052.                 * @param g The graphics context */
  1053.               public void paint(Graphics g) {
  1054.                   if (blown && blow_countdown < 0) {
  1055.                     blow_countdown = 20;
  1056.                   } else if (blown && blow_countdown < 10) {
  1057.                     g.drawImage(crashed_turbine_bm, 403, 73, plant);
  1058.                     if (blow_countdown == 8) {
  1059.                       plant.getAppletContext().showStatus("The turbine crashed");
  1060.                       plant.crashSound(8000);
  1061.                     }
  1062.                   } 
  1063.                   if (blown && blow_countdown > 0) {
  1064.                     blow_countdown--;
  1065.                     g.copyArea(403, 95, 145, 65,
  1066.                                403+rand(-2,2), 95+rand(-4,2));
  1067.                   } else if (!blown) blow_countdown = -1;
  1068.               }
  1069.           }
  1070.  
  1071.  
  1072. /**
  1073.  * Condenser component for the nuclear power plant
  1074.  *
  1075.  * @version 1.0f
  1076.  * @author Henrik Eriksson
  1077.  */
  1078.           class Condenser extends Tank {
  1079.  
  1080.               /** Water (surface) images for animation */
  1081.               protected static Image water_bm[] = new Image[3];
  1082.  
  1083.               /** Image of cooling pipe */
  1084.               protected static Image kylror_bm;
  1085.  
  1086.               /** Image of crashed condenser */
  1087.               protected static Image crashed_condenser_bm;
  1088.  
  1089.               /** Construct a condenser and initialize it. */
  1090.               Condenser() {
  1091.                   water_bm[0] = getImage("K_VATTEN_A_BM.GIF", water_bm[0]);
  1092.                   water_bm[1] = getImage("K_VATTEN_B_BM.GIF", water_bm[1]);
  1093.                   water_bm[2] = getImage("K_VATTEN_C_BM.GIF", water_bm[2]);
  1094.                   crashed_condenser_bm =
  1095.                      getImage("CRASHED_KONDENSOR_BM.GIF",crashed_condenser_bm);
  1096.                   kylror_bm = getImage("KYLROR_BM.GIF", kylror_bm);
  1097.                   label = "condenser";
  1098.                   waterLevel = 6000;
  1099.               }
  1100.  
  1101.               /** Advance the water-surface animation one step */
  1102.               void waterWave () {
  1103.                 if (++imageState >= water_bm.length) imageState = 0;
  1104.               }
  1105.  
  1106.               /** The color of water */
  1107.               private static Color waterColor = new Color(128,192,255);
  1108.  
  1109.               /** Paint operation for condenser
  1110.                 * @param g The graphics context */
  1111.               public void paint(Graphics g) {
  1112.                   if (pressure > 200) g.setColor(Color.red);
  1113.                   g.drawString((int)pressure+" bar", 520, 250);
  1114.                   g.setColor(waterColor);
  1115.                   int surfaceY = 440 - (int)waterLevel / 50;
  1116.                   g.fillRect(483, surfaceY+1, 108, 449-surfaceY);
  1117.                   g.drawImage(kylror_bm, 500, 349, plant);
  1118.                   g.setColor(Color.black);
  1119.                   g.drawImage(water_bm[imageState], 483, surfaceY, plant);
  1120.                   paintBubbles(g, 483, surfaceY, 590, 12, 8);
  1121.                   g.drawString("Level:", 615, 290);
  1122.                   g.drawString((int)waterLevel+" mm", 615, 305);
  1123.                   if (blown) {
  1124.                     g.drawImage(crashed_condenser_bm, 570, 214, plant);
  1125.                   }
  1126.               }
  1127.           }
  1128.  
  1129.  
  1130. /**
  1131.  * Generator component for the nuclear power plant
  1132.  *
  1133.  * @version 1.0f
  1134.  * @author Henrik Eriksson
  1135.  */
  1136.           class Generator extends Component {
  1137.  
  1138.               /** Output generator power (in MW) */
  1139.               int power;
  1140.  
  1141.               /** Set the value of a slot
  1142.                 * @param slot The slot name
  1143.                 * @param val The value */
  1144.               void setIntValue(String slot, int val) {
  1145.                 if (slot.equals("power")) power = val;
  1146.                 else super.setIntValue(slot, val);
  1147.               }
  1148.  
  1149.               /** Paint operation for generator
  1150.                 * @param g The graphics context */
  1151.               public void paint(Graphics g) {
  1152.                   g.drawString(power+" MW", 570, 95);
  1153.               }
  1154.           }
  1155.  
  1156.  
  1157.  
  1158. /**
  1159.  * The class Simulator is an abstact class for power-plant
  1160.  * simulators. The actual simulators are subclasses of this class.
  1161.  *
  1162.  * @see NuclearPlant
  1163.  * @version 1.0f
  1164.  * @author Henrik Eriksson
  1165.  */
  1166.           abstract class Simulator {
  1167.               /** The plant */
  1168.               protected NuclearPlant plant;
  1169.               abstract void start();
  1170.               abstract void timeStep(int n);
  1171.               abstract void blow(Component device);
  1172.               abstract void stop();
  1173.           }
  1174.  
  1175. /**
  1176.  * The class LocalSimulatorServer is a test class that simulates the
  1177.  * behavior of the simulator server. It is used for testing the
  1178.  * java client applet and its user interface.
  1179.  *
  1180.  * @see TestSimulatorServer
  1181.  * @see ClipsSimulatorServer
  1182.  * @version 1.0f
  1183.  * @author Henrik Eriksson
  1184.  */
  1185.          class LocalSimulator extends Simulator {
  1186.               /** The reactor and its components */
  1187.               protected Reactor reactor;    
  1188.  
  1189.               /** Valve object */
  1190.               protected Valve valve_1, valve_2, valve_3, valve_4;
  1191.  
  1192.               /** Pump object */
  1193.               protected Pump pump_1, pump_2, pump_3;
  1194.  
  1195.               /** The turbine */
  1196.               protected Turbine turbine;
  1197.  
  1198.               /** The condenser */
  1199.               protected Condenser condenser;
  1200.  
  1201.               /** The generator */
  1202.               protected Generator generator;
  1203.  
  1204.  
  1205.               /** Constructor for LocalSimulator. Wires objects based on the
  1206.                 * NuclearPlant components.
  1207.                 * @param p The current NuclearPlant object */
  1208.               public LocalSimulator(NuclearPlant p) {
  1209.                 plant = p;
  1210.                 reactor = p.reactor;
  1211.                 valve_1 = p.valve_1;
  1212.                 valve_2 = p.valve_2;
  1213.                 valve_3 = p.valve_3;
  1214.                 valve_4 = p.valve_4;
  1215.                 pump_1 = p.pump_1;
  1216.                 pump_2 = p.pump_2;
  1217.                 pump_3 = p.pump_3;
  1218.                 turbine = p.turbine;
  1219.                 condenser = p.condenser;
  1220.                 generator = p.generator;
  1221.               }
  1222.  
  1223.               /** Starts the local simulator. This method initializes
  1224.                 * the simulation variables (i.e., the plant is reset
  1225.                 * to steady state). */
  1226.               public void start() {
  1227.                 reactor.pressure = 288;
  1228.                 reactor.moderatorPercent = 50;
  1229.                 reactor.waterLevel = 1800;
  1230.                 reactor.blown = false;
  1231.                 reactor.overheated = false;
  1232.                 turbine.blown = false;
  1233.                 condenser.pressure = 40;
  1234.                 condenser.waterLevel = 6000;
  1235.                 condenser.blown = false;
  1236.                 generator.power = 622;
  1237.                 pump_1.status = 1;
  1238.                 pump_1.rpm = 1400;
  1239.                 pump_2.status = 1;
  1240.                 pump_2.rpm = 0;
  1241.                 pump_3.status = 1;
  1242.                 pump_3.rpm = 1285;
  1243.                 pump_1.blown = false;
  1244.                 pump_2.blown = false;
  1245.                 pump_3.blown = false;
  1246.                 valve_1.status = true;
  1247.                 valve_2.status = false;
  1248.                 valve_3.status = true;
  1249.                 valve_4.status = false;
  1250.               }
  1251.  
  1252.  
  1253.               /** Calculates the next state of the simulation. This
  1254.                 * calculation is perfomed locally in java.
  1255.                 * @param n The number of steps to calculate before returning */
  1256.               public void timeStep(int n) {
  1257.                 float v1, v2, v3, v4;
  1258.  
  1259.                 for (int i = 0; i < n; i++) {
  1260.                   if (!reactor.overheated) {
  1261.                     // Compute the flow through valve_1...
  1262.                     if (valve_1.status)
  1263.                       v1 = (reactor.pressure-condenser.pressure) / 10;
  1264.                     else v1 = 0;
  1265.                     // Compute the flow through valve_2...
  1266.                     if (valve_2.status)
  1267.                       v2 = (reactor.pressure-condenser.pressure) / 2.5f;
  1268.                     else v2 = 0;
  1269.  
  1270.                     // Compute the flow through valve_3 and pump_1...
  1271.                     if (valve_3.status)
  1272.                       if (pump_1.rpm > 0)
  1273.                         if (condenser.waterLevel > 0)
  1274.                           v3 = pump_1.rpm * 0.07f;
  1275.                         else v3 = 0;
  1276.                       else v3 = -30;
  1277.                     else v3 = 0;
  1278.  
  1279.                     // Compute the flow through valve_4 and pump_2...
  1280.                     if (valve_4.status)
  1281.                       if (pump_2.rpm > 0)
  1282.                         if (condenser.waterLevel > 0)
  1283.                           v4 = pump_2.rpm * 0.07f;
  1284.                         else v4 = 0;
  1285.                       else v4 = -30;
  1286.                     else v4 = 0;
  1287.  
  1288.                     // Scale the flow levels to allow frequent time steps
  1289.                     // (smother animation)
  1290.                     float factor = 0.5f;
  1291.                     v1 *= factor;
  1292.                     v2 *= factor;
  1293.                     v3 *= factor;
  1294.                     v4 *= factor;
  1295.  
  1296.                     // Compute new values for pressure and water levels...
  1297.                     float boiledRW = (100 - reactor.moderatorPercent)*2*(900 - reactor.pressure)/620;
  1298.                     boiledRW *= factor;
  1299.  
  1300.                     float cooledKP = (float)(pump_3.rpm * Math.sqrt(condenser.pressure) * 0.003f);
  1301.                     cooledKP *= factor;
  1302.  
  1303.                     float newRP = reactor.pressure - v1 - v2 + boiledRW/4;
  1304.  
  1305.                     // The steam flow to the condenser stops if the
  1306.                     // turbine is blown...
  1307.                     if (turbine.blown) v1 = 0;
  1308.  
  1309.                     // Compute new values for pressure and water levels...
  1310.                     float newKP = condenser.pressure + v1 + v2 - cooledKP;
  1311.                     float newRW = reactor.waterLevel + v3 + v4 - boiledRW;
  1312.                     float newKW = condenser.waterLevel - v3 - v4 + 4*cooledKP;
  1313.  
  1314.                     // Make adjustments for blown tanks...
  1315.                     if (reactor.blown) newRP = 0.15f * newRP;
  1316.                     if (condenser.blown) newKP = 0.2f * newKP;
  1317.                     // Check the computed values for illegal values...
  1318.                     if (newKW < 0) newKW = 0;
  1319.                     if (newKW > 9600) newKW = 9600;
  1320.                     if (newRW > 4700) newRW = 4700;
  1321.                     if (newKP < 0) newKP = 0;
  1322.                     if (newKP > 300) newKP = 300;
  1323.                     if (newRP > 800) newRP = 800;
  1324.  
  1325.                     // Adjust the generator power...
  1326.                     float newEffect;
  1327.                     if (valve_1.status && !turbine.blown)
  1328.                       newEffect = (newRP - newKP) * 2.5f;
  1329.                     else newEffect = 0;
  1330.  
  1331.                     // Assign the computed values...
  1332.                     generator.power = (int)newEffect;
  1333.                     condenser.pressure = newKP;
  1334.                     condenser.waterLevel = newKW;
  1335.                     reactor.pressure = newRP;
  1336.                     reactor.waterLevel = newRW;
  1337.  
  1338.                     // Rules for the plant...
  1339.                     if (condenser.waterLevel <= 0 && pump_1.rpm > 0)
  1340.                       pump_1.blow();
  1341.                     if (condenser.waterLevel <= 0 && pump_2.rpm > 0)
  1342.                       pump_2.blow();
  1343.  
  1344.                     if (pump_1.blown) pump_1.rpm = 0;
  1345.                     if (pump_2.blown) pump_2.rpm = 0;
  1346.                     if (pump_3.blown) pump_3.rpm = 0;
  1347.                     if (reactor.waterLevel < -1500) reactor.meltdown();
  1348.                     if (reactor.pressure >= 610) reactor.blow();
  1349.                     if (condenser.pressure >= 225) condenser.blow();
  1350.  
  1351.                     // R1 (safety rule for blown turbine)...
  1352. /* Disabled for now
  1353.                     if (turbine.blown) {
  1354.                       valve_1.status = false;
  1355.                       valve_2.status = true;
  1356.                       reactor.moderatorPercent = 100;
  1357.                       pump_1.rpm = 0;
  1358.                       valve_3.status = false;
  1359.                     }
  1360. */
  1361.  
  1362.                   } // if
  1363.  
  1364. try {Thread.sleep(200); } catch (InterruptedException e){}
  1365.  
  1366.                 }  // for
  1367.  
  1368.               }
  1369.  
  1370.               /** Blow up a device. 
  1371.                 * @param device The device to blow (e.g., a turbine object) */
  1372.               public void blow(Component device) {
  1373.                 device.blow();
  1374.               }
  1375.  
  1376.               /** Stop the simulation */
  1377.               public void stop() {
  1378.               }
  1379.  
  1380.           }
  1381.