Google Answers Logo
View Question
 
Q: JAVA GUI PROGRAMMING program code ( Answered 4 out of 5 stars,   0 Comments )
Question  
Subject: JAVA GUI PROGRAMMING program code
Category: Computers > Programming
Asked by: wcryder-ga
List Price: $40.00
Posted: 12 Nov 2002 20:16 PST
Expires: 12 Dec 2002 20:16 PST
Question ID: 106592
I need you to write four .java files: Chaser.java, Runner.java,
Random.java, and Custom.java that produce the characteristics given
below. There is a base class Creature, with source code in
Creature.java. Four classes derived from Creature shall be as follows:

Notes for CreatureWorld.java 

This program exhibits the behavior of 4 types of "creatures" as they
interact with each other in a world consisting of a region on your
terminal screen. It can be thought of as a simple "artificial life"
simulation of the interaction of these creatures in their small world.
To keep it simple, the interaction between the creatures is restricted
in a way that is described below. Each creature is implemented as a
Java object, and so it is an instance of some Java class.
The code I have already written is below.  They are the files
CreatureWorld.java and Creature.java. When writing the code please try
to keep at a level at which I can understand.  I do not consider
myself an advanced programmer and want to be able to interpret the
code given to me instead of just having a program that compiles.

a. The "Chaser" class. A Chaser tries to catch other creatures. When
it gets a chance to interact with another Creature, a Chaser moves to
a location which, of all its neighboring locations on the screen, is
nearest to the other creature. A Chaser creature appears on the screen
as a red filled circle 15 pixels in diameter, with its center at the
Chaser's location.

b. The "Runner" class. A Runner tries to escape from other creatures.
In each interaction with another creature, a Runner moves to a
location which, of all its neighboring locations, is farthest from the
other creature. A Runner creature appears on the screen as a green
filled square 15 pixels on a side, with its center at the Runner's
location.

c. The "Random" class. A Random doesn't care about other creatures.
When it gets a chance to interact with another creature, a Random
creature moves to a randomly selected location, no matter where the
other creature is. The new location must be no more than 20 pixels
horizontally and 20 pixels vertically of its previous location. A
Random creature appears on the screen as a blue 'X', with the center
of the X at the Random's location. The 'X' should be 15 pixels high
and 15 pixels wide.

d. Here you get to use your imagination. A Custom creature can respond
to the other creature in any way you like, as long as the way it does
this is different from what the other 3 types of creature do, and as
long as it does something. In addition, it can display itself in any
way you like, as long as it is different from the other 3 types, and
as long as it displays visibly, at its current location. Within these
constraints, anything is fine, so have fun.
In any case, no creature (even a Custom one) should ever move outside
the boundaries of the "world"; when it gets to an edge, it should move
as best it can within the constraints of the boundary. (This must be
true even if the Creature it is reacting to is somehow outside the
boundary)
When the program runs, the user is given the opportunity to select the
types of Creature to observe, their initial location, and how many
steps to run the simulation. To exit the simulation, the user can
close the application window.

The base class constructor in Creature.java may handle all of the
initialization you need; but since constructors are not inherited, you
have to define your own in the derived classes. The constructor must
take 2 int arguments, the initial x and y coordinates of the Creature.
Override the reactTo() and paint() methods to do the appropriate thing
for each derived class; the ones in the base class are abstract, so do
not include method bodies. (the base class instance variables have
protected visibility, so they are directly accessible within methods
of derived classes.) These methods will be called from the
CreatureWorld application, after the user clicks the START button to
begin the simulation. The basic animulation loop in CreatureWorld
looks like this (some pseudocode here):

    // loop for the right number of animation steps
    for(int step = 1; step<=steps; step++) {

      // get a Rectangle specifying the size of the "world"
      Rectangle r = Rectangle_For(world);

      // react each pair of Creatures in order of their indices
      int nCreatures = Number_Of_Creatures();
      for(int ic1 = 0; ic1 < nCreatures; ic1++) {
	for(int ic2 = 0; ic2 < nCreatures; ic2++) {
	  // make Creature indexed ic1 move in reaction to
	  // creature indexed ic2; but don't bother if ic1 == ic2
	  if (ic1 == ic2) continue;
          Creature c1 = Creature_Indexed(ic1);
	  Creature c2 = Creature_Indexed(ic2);
	  c1.reactTo(c2,r);
	}
      }

      // display the Creatures at their new location
      Graphics g = Graphics_For(world);	
      for(int ic = 0; ic < nCreatures; ic++) {
        Creature c1 = Creature_Indexed(ic);
	c1.paint(g);
      }
    }

The loop structure ensures that each Creature gets to reactTo() every
other one before the result of each animation step is displayed; but
the order in which these reactions take place depends on the order in
which the Creatures were added, and different behaviors can happen as
a result. If there are more than 2 Creatures involved, their
interactions can be hard to predict (that's why simulations are
useful).

To implement the paint() method, note that a java.awt.Graphics object
is passed as argument. The Graphics class defines lots of instance
methods for doing graphics.  Here are some suggested prototypes for
some of the methods that I would prefer you to use:

public void drawLine(int x1, int y1, int x2, int y2);
public void drawOval(int x, int y, int width, int height);
public void drawRect(int x, int y, int width, int height);
public void drawString(String str, int x, int y);
public void fillOval(int x, int y, int width, int height);
public void fillRect(int x, int y, int width, int height);
public void setColor(Color c);

Note that the x, y location for rectangles and ovals is the upper left
"corner" of the rectangle or oval.

Make the reactTo() method take two arguments: a Creature to react to,
and a Rectangle that specifies the limits of allowed movement. The
Creature must not move outside that Rectangle. Rectangle is a class in
the java.awt package. It is a somewhat unusual class, in that its
instance variables are public:

 public int x; // The x coordinate of the upper left corner of the
rectangle.
 public int y; // The y coordinate of the rectangle.
 public int width; // The width of the rectangle.
 public int height; // The height of the rectangle.

Rectangle also defines many instance methods. One you may find useful
has this prototype:
//Checks whether this rectangle contains the point at the specified
location (x, y)
public boolean contains(int x, int y) 

The hard part is coming up with an algorithm for finding a "best"
position for a Chaser or a Runner creature to move to, when it reacts
to another creature. Here's a hint for one possible way to do this. A
creature has a certain x,y location on the "world Canvas". The
neighboring locations are the 9 pixels with coordinates
	x-1,y-1   x,y-1   x+1,y-1

	x-1,y     x,y     x+1,y

	x-1,y+1   x,y+1   x+1,y+1

So, all combinations of offsets from the current x and y coordinates
can be tried with a doubly-nested for loop. You can pick the one that
is "best" according to whether the creature wants to be closer or
farther from the location of the other creature (but remember to stay
within the boundaries of the Rectangle passed to the reactTo()
method).

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

/***********************************************************
  * class CreatureWorld
  * CreatureWorld extends JFrame to create a GUI "artificial life"
simulation.
***********************************************************/
public class CreatureWorld extends JFrame {

  /**
   * Initialize the application JFrame.
   */
  public CreatureWorld() {
    super("Creature World"); // initialize JFrame, with a title
    // set size and location of the application JFrame
    setBounds(APPLOC_X,APPLOC_Y,APPFRAMEWIDTH,APPFRAMEHEIGHT);

    // get the JFrame's contentPane, to add JComponents to
    Container thisPane = getContentPane();
    // create panel for North region of Frame
    // holds messageLabel
    JPanel northPanel = new JPanel();
    JPanel messagePanel = new JPanel();
    messageLabel = new JLabel("Welcome to the Creature World!  Place
Creatures, then START");
    northPanel.add(messageLabel);
    thisPane.add(northPanel,BorderLayout.NORTH);
    // create panel for South region of Frame
    // holds two further JPanels:
    // one for steps JTextField and its associated JLabels,
    // one for Creature placement buttons
    JPanel southPanel = new JPanel();
    southPanel.setLayout(new GridLayout(2,1));
    // set up the panel for displaying steps info
    JPanel stepsPanel = new JPanel();
    stepsPanel.add(new JLabel("Steps:",JLabel.RIGHT));
    stepsField = new JTextField("   100");
    stepsPanel.add(stepsField);
    stepsPanel.add(new JLabel("  Steps done: ",JLabel.RIGHT));
    stepsLabel = new JLabel("0    ",JLabel.LEFT);
    stepsPanel.add(stepsLabel);
    // set up the panel for displaying Creature placement buttons
    // ActionListener for a Creature placement button will just
    // call startCreaturePlacement(ActionEvent e)
    ActionListener startCreaturePlacement =
      new ActionListener() { // anon. inner class
      public void actionPerformed(ActionEvent e) {
        startCreaturePlacement(e); }};
    JPanel buttonPanel = new JPanel();
    buttonPanel.add(new JLabel("Creature types: "));
    JButton chaserButton = new JButton("Chaser");
  JButton chaserButton = new JButton("Chaser");
    chaserButton.setBackground(Color.red);
    buttonPanel.add(chaserButton);
    chaserButton.addActionListener(startCreaturePlacement);
    JButton runnerButton = new JButton("Runner");
    runnerButton.setBackground(Color.green);
    buttonPanel.add(runnerButton);
    runnerButton.addActionListener(startCreaturePlacement);
    JButton randomButton = new JButton("Random");
    randomButton.setBackground(Color.blue);
    buttonPanel.add(randomButton);
    randomButton.addActionListener(startCreaturePlacement);
    JButton customButton = new JButton("Custom");
    buttonPanel.add(customButton);
    customButton.addActionListener(startCreaturePlacement);

    southPanel.add(buttonPanel);    southPanel.add(stepsPanel);
    thisPane.add(southPanel,BorderLayout.SOUTH);

    // put Start button in East region
    JButton startButton = new JButton("START");
    thisPane.add(startButton,BorderLayout.EAST);
    startButton.addActionListener(new ActionListener () {
      public void actionPerformed(ActionEvent e) {
        doSimulation();
      }});
    // put Clear button in West region
    JButton clearButton = new JButton("CLEAR");
    thisPane.add(clearButton,BorderLayout.WEST);
    clearButton.addActionListener(new ActionListener () { // anon.
inner class
      public void actionPerformed(ActionEvent e) { // implement
actionPerformed
        doClear();  // to call our private method
      }});

    // create the world JPanel.  Use an anonymous inner class to
    // override the paintComponent() method to display such Creatures
as
    // may exist
    world = new JPanel() {
      public void paintComponent(Graphics g) {
        super.paintComponent(g); // superclass version clears
background
        // Ask each Creature to draw itself
        for(int i=0; i<creatureVec.size(); i++) {
          Creature c = (Creature) creatureVec.get(i);
          c.paint(g);
        }
      }
    };
    world.setBackground(Color.white);
    world.setSize(WORLDWIDTH, WORLDHEIGHT);
    // the world gets a MouseListener
    world.addMouseListener(new MouseAdapter() { // anon. inner class
      public void mouseClicked(MouseEvent e) {  // override
mouseClicked
        handleMouseClicked(e);  // to call our private method
      }});

    thisPane.add(world,BorderLayout.CENTER);

    // give the overall Frame a WindowListener to handle closing
events
    addWindowListener(new WindowAdapter() { // anonymous inner class
      public void windowClosing(WindowEvent e) {
        dispose();
        System.exit(0);
      }});
  }

  // a mouse clicked event handler for the world: place a Creature
  private void handleMouseClicked(MouseEvent e) {
    // if we're not placing a Creature, explain and return
    if(placeCreatureType == NONE) {
      announce("Select a Creature type first, then click to place!");
      return;
    }
    // okay, now we're placing a kind of Creature.
    // get the x,y coordinates of the mouse click
    int x = e.getX();  int y = e.getY();
    // pointer to the new creature we will create
    Creature newCreature = null;
    // create a new Creature of the appropriate type
    switch(placeCreatureType) {
    case CHASER:
      newCreature = new Chaser(x,y);
      break;
    case RUNNER:
      newCreature = new Runner(x,y);
      break;
    case RANDOM:
      newCreature = new Random(x,y);
      break;
    case CUSTOM:
      newCreature = new Custom(x,y);
      break;
    default:
      System.err.println("Shouldn't happen! Bad creature type: " +
placeCreatureType);
      System.exit(-1);
    }
    // put it in the creatures vector
    creatureVec.add(newCreature);
    // display the new creature, and finish up
    world.paintImmediately(world.getVisibleRect());
    // done placing
    placeCreatureType = NONE;
    setCursor(Cursor.getDefaultCursor());
    announce("Place another creature, or push START.");
  }

  // user wants to place a Creature
  private void startCreaturePlacement(ActionEvent e) {
    // we use CROSSHAIR_CURSOR to indicate placement mode
    setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
    String label = e.getActionCommand();
    // user wants to place a Chaser
    if(label.equals("Chaser")) {
      placeCreatureType = CHASER;
      announce("Click to place a Chaser...");
    }
    // user wants to place a Runner
    if(label.equals("Runner")) {
      placeCreatureType = RUNNER;
      announce("Click to place a Runner...");
    }
    // user wants to place a Random
    if(label.equals("Random")) {
      placeCreatureType = RANDOM;
      announce("Click to place a Random...");
    }
    // user wants to place a Custom
    if(label.equals("Custom")) {
      placeCreatureType = CUSTOM;
      announce("Click to place a Custom...");
    }
  }

  // user wants to clear the world of Creatures
  private void doClear() {
    // get rid of current Creatures
    creatureVec.clear();
    // indicate we are not in creature-placement mode
    placeCreatureType = NONE;
    setCursor(Cursor.getDefaultCursor());
    stepsLabel.setText("0");
    // clear the world display
    world.paintImmediately(world.getVisibleRect());
    announce("Welcome to the Creature World!  Place some Creatures,
then START");
  }

  private void doSimulation() {
    if (creatureVec.size() < 2) {
      announce("You need at least 2 creatures. Please place more!");
      return;
    }
    int steps = 0;
    // read the text in the stepsField to find how many steps in the
animation
    try{
      steps = Integer.parseInt(stepsField.getText().trim());
    } catch (NumberFormatException ex) {
      announce("Formatting error in Steps text field. Try again");
      return;
    }
    announce("Running...");

    // loop for the right number of animation steps
    for(int step = 1; step<=steps; step++) {
      // get a Rectangle specifying the size of the "world"
      Rectangle r = new
Rectangle(world.getSize().width,world.getSize().height);
      // react each pair of Creatures
      for(int ic1 = 0; ic1 < creatureVec.size(); ic1++) {
        for(int ic2 = 0; ic2 < creatureVec.size(); ic2++) {
          // make Creature indexed ic1 move in reaction to
          // creature indexed ic2; but don't bother if ic1 == ic2
          if (ic1 == ic2) continue;
          Creature c1 = (Creature) creatureVec.get(ic1);
          Creature c2 = (Creature) creatureVec.get(ic2);
          c1.reactTo(c2,r);
        }
      }
      // display the Creatures at their new location
      world.paintImmediately(r);
      // show how many steps we've done
      stepsLabel.setText(Integer.toString(step));
      // guess we have to explicitly repaint the JLabel..?
      stepsLabel.paintImmediately(stepsLabel.getVisibleRect());
      // sleep for a short interval so everything doesn't happen at
once
      try {
        Thread.sleep(msBetweenFrames);
      } catch (Exception ex) {}
    }
    // done!
    announce("Click START to continue, CLEAR to start over");
  }



  // print a string in the messageLabel
  private void announce(String s) {
    messageLabel.setText(s);
  }

  // just paint the world with the background color
  private void clearWorld() {
      int width = world.getSize().width;
      int height = world.getSize().height;
      world.getGraphics().clearRect(0,0,width,height);
  }


  // named constants corresponding to the Creature types
  public static final int NONE = 0;
  public static final int CHASER = 1;
  public static final int RUNNER = 2;
  public static final int RANDOM = 3;
  public static final int CUSTOM = 4;

  // initial dimensions of the application frame
  private static final int APPFRAMEWIDTH = 600;
  private static final int APPFRAMEHEIGHT = 400;
  // initial location of the application frame on the display
  private static final int APPLOC_X = 50;
  private static final int APPLOC_Y = 50;
  // initial dimensions of the world panel
  private static final int WORLDWIDTH = 400;
  private static final int WORLDHEIGHT = 300;

  // milliseconds to pause between frames of the animation
  private int msBetweenFrames = 60;

  private JPanel world;
  private Vector creatureVec = new Vector();
  private int placeCreatureType = NONE;

  private JTextField stepsField;
  private JLabel stepsLabel;
  private JLabel messageLabel;

  /**
   * Start the CreatureWorld application
   */
  public static void main(String args[]) {
    (new CreatureWorld()).setVisible(true);
  }

}


import java.awt.*;

/***********************************************************
  * class Creature
  * Creature is a base class intended to be subclassed to
  * model various kinds of creatures.  See the README for details.

***********************************************************/
public abstract class Creature {

  /**
   * Initialize a Creature with a x,y location.
   */
  protected Creature(int x, int y) {
    this.x = x;
    this.y = y;
  }

  /**
   * Change this Creature's location to respond to
   * the other Creature.
   * This method is abstract; it
   * must be overridden in derived classes.  The Creature must
   * never move outside the limits of the given Rectangle.
   * @param other The other creature.
   * @param world A rectangle that specifies the limits of the world.
   */
  public abstract void reactTo(Creature other, Rectangle world);

  /**
   * Display the Creature at its current location on the
   * given Graphics object.  This method is abstract; it
   * must be overridden in derived classes
   * @param g The Graphics object to use for display.
   */
  public abstract void paint(Graphics g);

  /**
   * return the current x coordinate of the Creature's location.
   */
  public final int getLocationX() { return x; }

  /**
   * return the current y coordinate of the Creature's location.
   */
  public final int getLocationY() { return y; }

  /** return, as a double, the distance in pixels
   * between this Creature and another.
   */
  public double distanceTo(Creature other) {
    double dx = this.x - other.x;
    double dy = this.y - other.y;
    return Math.sqrt(dx*dx + dy*dy);
  }

  /** return, as a double, the angle in radians
   * between this Creature and another.
   */
  public double angleTo(Creature other) {
    double dx = this.x - other.x;
    double dy = this.y - other.y;
    return Math.atan2(dy,dx);
  }

  protected int x;  // current x coordinate of Creature
  protected int y;  // current y coordinate of Creature

}

Clarification of Question by wcryder-ga on 12 Nov 2002 21:45 PST
Just a note...I will be canceling this question if it is not answered
by 8:00 am nov. 13 (PST).

Request for Question Clarification by rbnn-ga on 13 Nov 2002 06:38 PST
How about 10 am PST?
Answer  
Subject: Re: JAVA GUI PROGRAMMING program code
Answered By: rbnn-ga on 13 Nov 2002 07:40 PST
Rated:4 out of 5 stars
 
As always, please use the "Request Clarification" button to request
clarification or solicit additional features or functionality before
rating this answer.

I've interpreted the question to mean that you are looking for
something fairly simple, rather than a fancy animation with many
features and sophisticated graphics.

I've implemented the constraints in the files:

Creature.java
CreatureWorld.java

Custom.java
Random.java
Chaser.java
Runner.java

Because it is kind of messy to cut and paste java code here, I have
placed them in the URLs:

http://www.rbnn.com/google/Creature.java
http://www.rbnn.com/google/CreatureWorld.java
http://www.rbnn.com/google/Custom.java
http://www.rbnn.com/google/Random.java
http://www.rbnn.com/google/Chaser.java
http://www.rbnn.com/google/Runner.java

I did not change CreatureWorld at all.

I modified Creature by adding the single method:

    public double distance2FromPoint(int x, int y){
	return Math.pow(x-this.x,2)+Math.pow(y-this.y,2);
    }

This gives the square of the distance of a creature from a given
point, and is used by Runner, Chaser, and Custom.

(If it is not allowed to change Creature.java, just move this method
to the classes where it is used.)


The Custom creature displays as a black rectangle. It moves diagonally
and changes direction when either it hits a wall or if it is within a
distance 10 of another creature.

Note that two creatures can be on the same coordinate (and two Chaser
creatures often are).
wcryder-ga rated this answer:4 out of 5 stars
code lacked commenting, but otherwise excellent answer! happy with
results and prompt answer time!

Comments  
There are no comments at this time.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy