import biosim.*; import java.awt.*; import java.applet.*; import java.util.*; /** * A class to encapsulate the graphical representation of an Organism. * An Organism is represented graphically as a circle, in a color * dependent on its class. The OrgRep class as written only distinguishes * between Predators and other Organisms. */ class OrgRep { /** * The Organism to represent. */ Organism organism; /** * The color to display this OrgRep. */ Color color; /** * Construct a new OrgRep to represent the specified Organism. * The color of the OrgRep is decided from the class of the Organism. * This version only knows about two classes of Organism: biosim.Organism * and biosim.Predator. The Predators are drawn in red, and the * other Organisms are drawn in cyan. To extend OrgRep to include other * classes of Organisms, one would need only override the constructor. */ public OrgRep(Organism org) { organism = org; if (org instanceof Predator) { color = Color.red; } else { color = Color.cyan; } } /** * Returns the color of this OrgRep. */ public Color getColor() { return color; } /** * Returns the Organism being represented. */ public Organism getOrganism() { return organism; } /** * Returns true if the specified x, y coordinates * lie inside the Organism represented by this OrgRep. */ public boolean inside(int x, int y) { XYPair p = new XYPair(x, y); if (organism.distanceTo(p) <= organism.getRadius()) { return true; } else { return false; } } /** * Draws this OrgRep as a circle on the specified Graphics * context, in the appropriate color. */ public void draw(Graphics g) { Color originalColor = g.getColor(); Point pos = organism.getPosition().asPoint(); int r = (int) organism.getRadius(); g.setColor(color); g.fillArc(pos.x, pos.y, r, r, 0, 360); g.setColor(originalColor); } } class EcoCanvas extends Canvas implements Observer, Runnable { Ecosystem ecosystem; Thread drawThread; Vector orgRepList; /** * Construct a new EcoCanvas to observe the specified Ecosystem. */ public EcoCanvas(Ecosystem ecosystem) { super(); this.ecosystem = ecosystem; ecosystem.addObserver(this); orgRepList = new Vector(); this.setBackground(Color.black); } /** * Not to be confused with update(Graphics g), this method is called * when a change occurs in an Observable object (namely the * Ecosystem) being observed by this class. The Ecosystem calls * this method once at the end of each iteration of its main loop. * * When this method is called, the EcoCanvas creates a brand * new list of OrgReps from the organisms currently in the * ecosystem, and then creates and starts a thread to draw them. */ public void update(Observable obs, Object arg) { orgRepList = new Vector(); Vector orglist = ecosystem.organisms; Organism org; synchronized (orglist) { for (int i = 0; i < orglist.size(); i++) { org = (Organism) orglist.elementAt(i); orgRepList.addElement(new OrgRep(org)); } } drawThread = new Thread(this); drawThread.start(); } /** * All the EcoCanvas needs to do when it is run * is to repaint the Organisms. */ public void run() { repaint(); } /** * The paint() method draws all of the OrgReps in the orgRepList. */ public void paint(Graphics g) { OrgRep org; synchronized (orgRepList) { for (int i = 0; i < orgRepList.size(); i++) { org = (OrgRep) orgRepList.elementAt(i); org.draw(g); } } } /** * Resizes the ecosystem before calling the inherited resize() */ public void resize(int width, int height) { ecosystem.resize(width, height); super.resize(width, height); } /** * Resizes the ecosystem before calling the inherited reshape() */ public void reshape(int x, int y, int width, int height) { ecosystem.resize(width, height); super.reshape(x, y, width, height); } /** * Returns false to insure that the event gets handled by the parent Component. */ public boolean mouseDown(Event e, int x, int y) { return false; } } public class BioSimulation extends Applet { // The Ecosystem we are observing. Ecosystem ecosystem; // Are we adding or deleting Organisms? String currentMode = "Add Organisms"; // What kind of Organisms are we adding? String currentOrgType = "Organism"; // COMPONENTS OF THE TOP PANEL Panel topMainPanel; Panel firstSubPanel; Panel secondSubPanel; Choice modeChoice; Label typeLabel; Choice typeChoice; Button addButton; // IN THE CENTER IS THE ECOCANVAS EcoCanvas ecoCanvas; // COMPONENTS OF THE BOTTOM PANEL Panel bottomPanel; Button startButton; Button stopButton; Button resetButton; public void init() { setLayout(new BorderLayout()); // THE TOP PANEL IS FOR ADDING ORGANISMS topMainPanel = new Panel(); topMainPanel.setLayout(new BorderLayout()); firstSubPanel = new Panel(); firstSubPanel.setLayout(new FlowLayout()); topMainPanel.add("North", firstSubPanel); secondSubPanel = new Panel(); secondSubPanel.setLayout(new FlowLayout()); topMainPanel.add("South", secondSubPanel); modeChoice = new Choice(); modeChoice.addItem("Add Organisms"); modeChoice.addItem("Remove Organisms"); modeChoice.select(currentMode); firstSubPanel.add(modeChoice); typeLabel = new Label("Type: "); secondSubPanel.add(typeLabel); typeChoice = new Choice(); typeChoice.addItem("Organism"); typeChoice.addItem("Predator"); typeChoice.select(currentOrgType); secondSubPanel.add(typeChoice); addButton = new Button("Add Random"); secondSubPanel.add(addButton); this.add("North", topMainPanel); // THE ECOCANVAS IS FOR DISPLAYING THE SIMULATION ecosystem = new Ecosystem(); ecoCanvas = new EcoCanvas(ecosystem); this.add("Center", ecoCanvas); // THE BOTTOM PANEL IS FOR CONTROLLING THE FLOW // OF THE SIMULATION. bottomPanel = new Panel(); bottomPanel.setLayout(new FlowLayout()); startButton = new Button("Start"); stopButton = new Button("Stop"); resetButton = new Button("Reset"); bottomPanel.add(startButton); bottomPanel.add(stopButton); bottomPanel.add(resetButton); this.add("South", bottomPanel); layout(); } public void addSomeOrganisms() { Random r = new Random(); Organism org; Vector tempList = new Vector(); for (int i = 0; i < 5; i++) { int x = Math.abs(r.nextInt() % ecosystem.size().width); int y = Math.abs(r.nextInt() % ecosystem.size().height); if (currentOrgType.equals("Predator")) { org = new Predator(x, y, ecosystem); } else { org = new Organism(x, y, ecosystem); } tempList.addElement(org); } ecosystem.addOrganisms(tempList); } public void start() { ecosystem.resize(ecoCanvas.size().width, ecoCanvas.size().height); } public void stop() { ecosystem.stop(); } public boolean action(Event evt, Object what) { if (evt.target.equals(startButton)) { ecosystem.start(); return true; } else if (evt.target.equals(stopButton)) { ecosystem.stop(); return true; } else if (evt.target.equals(resetButton)) { ecosystem.reset(); return true; } else if (evt.target.equals(addButton)) { addSomeOrganisms(); return true; } else if (evt.target.equals(typeChoice)) { currentOrgType = typeChoice.getSelectedItem(); return true; } else if (evt.target.equals(modeChoice)) { currentMode = modeChoice.getSelectedItem(); if (currentMode.equals("Remove Organisms")) { typeChoice.disable(); addButton.disable(); return true; } else { typeChoice.enable(); addButton.enable(); return true; } } else { return false; } } public boolean mouseDown(Event evt, int x, int y) { Organism org; OrgRep orgRep; // First, correct for the offset of the EcoCanvas. Rectangle r = ecoCanvas.bounds(); x -= r.x; y -= r.y; if (currentMode.equals("Remove Organisms")) { synchronized (ecoCanvas.orgRepList) { for (int i = 0; i < ecoCanvas.orgRepList.size(); i++) { orgRep = (OrgRep) ecoCanvas.orgRepList.elementAt(i); if (orgRep.inside(x, y)) { ecosystem.removeOrganism(orgRep.getOrganism()); return true; } } } } else if (currentOrgType.equals("Predator")) { org = new Predator(x, y, ecosystem); ecosystem.addOrganism(org); return true; } else if (currentOrgType.equals("Organism")){ org = new Organism(x, y, ecosystem); ecosystem.addOrganism(org); return true; } return false; } }