import java.awt.*;
import java.*;
import java.lang.*;                                    
import java.awt.event.*;
import java.applet.*;
import java.io.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.loaders.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.keyboard.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.behaviors.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.image.*;

public class PredPrey3D extends java.applet.Applet implements Runnable, ActionListener, AdjustmentListener, WindowListener{
        Image buf, graphImg;
        Graphics gbuf, graphG, graphBuf;
        Thread runner;

        final int COUNT_LIMIT= 100, SPACE= 300/COUNT_LIMIT, VECTOR_SIZE= 20, SHEEP= 1, WOLF= 1, GRASS= 2, sheepSight= 50, wolfSight= 75, MAX_MEM= 25, MIN_MEM= -25;
        final float initAnimalSize= .25f, initGrassLength= .3f, GRASS_LENGTH= 1f, SHEEP_SIZE= .5f, WOLF_SIZE= 1f;
        int width= 300, length= 300, time= 0, countIndex= -1, oldestSheepAge= 0, amountGrass= VECTOR_SIZE,
                numSheepAlive, sheepTime= 0, sheepSize, sheepTotalCount= 0, SHEEP_AGE= 400, SHEEP_EAT= 200, SHEEP_REP= SHEEP_AGE/4,
                numWolfAlive, wolfTime= 0, wolfSize, wolfTotalCount= 0, WOLF_AGE= 600, WOLF_EAT= 300, WOLF_REP= WOLF_AGE/4;
        double distance, tempDist, angle;
        String numAnimal;
        Integer num;
        boolean runBefore= false, done= false;
        Vector3d grassLoc= new Vector3d();
        Vector sheep, wolf, grass, 
                                sheepCount, sheepBranch,// sheepPos,
                                wolfCount, wolfBranch,// wolfPos,
                                grassBranch;//, grassPos;

        Button reset, exit, opt, dispGraph, hlp;
        Frame options= new Frame("Preditor/Prey Options"),
                         graph= new Frame("Preditor/Prey Graph"),
                         help= new Frame("Help");
        Panel bottom, graphPan;
        ScrollPane graphScroll;
        TextArea helpText;
	
        Scrollbar       wolfNumScroll= new Scrollbar(Scrollbar.HORIZONTAL, 2, 1, 1, 6), 
                                        wolfAgeScroll= new Scrollbar(Scrollbar.HORIZONTAL, WOLF_AGE, 10, 100, 1201), 
                                        wolfEatScroll= new Scrollbar(Scrollbar.HORIZONTAL, WOLF_EAT, 10, 50, 601), 
                                        sheepNumScroll= new Scrollbar(Scrollbar.HORIZONTAL, 2, 1, 1, 11), 
                                        sheepAgeScroll= new Scrollbar(Scrollbar.HORIZONTAL, SHEEP_AGE, 10, 100, 1001), 
                                        sheepEatScroll= new Scrollbar(Scrollbar.HORIZONTAL, SHEEP_EAT, 10, 50, 501);
        TextField wolfNumText, wolfAgeText, wolfEatText, sheepNumText, sheepAgeText, sheepEatText;
        Grass3D g, tempGrass;
        Sheep3D s, tempSheep;
        Wolf3D w, tempWolf;
        Material wolfMaterial, sheepMaterial, grassMaterial;
        Appearance wolfAppear, sheepAppear, grassAppear;

        Canvas3D c= new Canvas3D(null);
        SimpleUniverse u= new SimpleUniverse(c);
        BranchGroup objRoot= new BranchGroup(), animalRoot= buildBranchGroup();
        BoundingSphere bounds= new BoundingSphere(new Point3d(), 1000);
        Font3D f3d= new Font3D(new Font("Helvetica", Font.PLAIN, 1), new FontExtrusion());
        ViewingPlatform plat= u.getViewingPlatform();
        TransformGroup viewTrans= plat.getViewPlatformTransform();
        BranchGroup txtTrans= buildBranchGroup();

        /*
                createSceneGraph:
                        builds the 3D world
                        receives the SimpleUniverse to manipulate, used to set up keyboard navigation control
                        returns finished BrachGroup
        */

        public BranchGroup createSceneGraph() { 	
                buildFrames();
                viewTrans.addChild(txtTrans);
                System.out.println("Creating scene graph");
                objRoot.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
                objRoot.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                objRoot.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);

        //materials for animals	
                sheepMaterial= new Material(new Color3f(0f, 0f, .5f), new Color3f(0f, 0f, .5f), new Color3f(.7f, .7f, .7f), new Color3f(1f, 1f, 1f), 100f);
                sheepMaterial.setCapability(Material.ALLOW_COMPONENT_READ);
                sheepMaterial.setCapability(Material.ALLOW_COMPONENT_WRITE);
                wolfMaterial= new Material(new Color3f(.5f, 0f, 0f), new Color3f(.5f, 0f, 0f), new Color3f(.7f, .7f, .7f), new Color3f(1f, 1f, 1f), 100f);
                wolfMaterial.setCapability(Material.ALLOW_COMPONENT_READ);
                wolfMaterial.setCapability(Material.ALLOW_COMPONENT_WRITE);
                grassMaterial= new Material(new Color3f(0f, .3f, 0f), new Color3f(0f, .3f, 0f), new Color3f(.7f, .7f, .7f), new Color3f(1f, 1f, 1f), 100f);
                grassMaterial.setCapability(Material.ALLOW_COMPONENT_READ);
                grassMaterial.setCapability(Material.ALLOW_COMPONENT_WRITE);
	
        //      appearce objects
                wolfAppear= new Appearance();
                wolfAppear.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0f));
                wolfAppear.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
                TextureAttributes texAttr= new TextureAttributes();
                texAttr.setCapability(TextureAttributes.ALLOW_MODE_WRITE);
                texAttr.setCapability(TextureAttributes.ALLOW_BLEND_COLOR_WRITE);
                texAttr.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE);
                texAttr.setTextureMode(TextureAttributes.DECAL);
                texAttr.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
                wolfAppear.setTextureAttributes(texAttr);
                wolfAppear.setMaterial(wolfMaterial);
        	
                grassAppear= new Appearance();
                grassAppear.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0f));
                grassAppear.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
                texAttr= new TextureAttributes();
                texAttr.setCapability(TextureAttributes.ALLOW_MODE_WRITE);
                texAttr.setCapability(TextureAttributes.ALLOW_BLEND_COLOR_WRITE);
                texAttr.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE);
                texAttr.setTextureMode(TextureAttributes.DECAL);
                texAttr.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
                grassAppear.setTextureAttributes(texAttr);
                grassAppear.setMaterial(grassMaterial);
        	
                sheepAppear= new Appearance();
                sheepAppear.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0f));
                sheepAppear.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
                texAttr= new TextureAttributes();
                texAttr.setCapability(TextureAttributes.ALLOW_MODE_WRITE);
                texAttr.setCapability(TextureAttributes.ALLOW_BLEND_COLOR_WRITE);
                texAttr.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE);
                texAttr.setTextureMode(TextureAttributes.DECAL);
                texAttr.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
                sheepAppear.setTextureAttributes(texAttr);
                sheepAppear.setMaterial(sheepMaterial);

        //set up animals	
                setUp();
        	
        //background & floor
                Background bg= new Background(new Color3f(0f, 0f, 0f));
                bg.setApplicationBounds(bounds);
                TransformGroup floor= new TransformGroup();
                Transform3D ft= new Transform3D();
                ft.setTranslation(new Vector3d(0f, -.5f, 0f));
                floor.setTransform(ft);
                Appearance fa= new Appearance();
                Material fm= new Material(new Color3f(0f, .3f, 0f), new Color3f(0f, .3f, 0f), new Color3f(.7f, .7f, .7f), new Color3f(1f, 1f, 1f), 100f);
                fa.setMaterial(fm);
                Box fl= new Box((float)width, 0f, (float)length, Box.GENERATE_TEXTURE_COORDS | Box.GENERATE_NORMALS, fa);
                floor.addChild(fl);
                objRoot.addChild(floor);
                objRoot.addChild(bg);

        //lights for the scene
                AmbientLight al= new AmbientLight();
                al.setInfluencingBounds(bounds);
                objRoot.addChild(al);
                PointLight pl= new PointLight(true, new Color3f(1f, 1f, 1f), new Point3f(5f, 5f, 5f), new Point3f(1f, 0f, 0f));
                pl.setInfluencingBounds(bounds);
                objRoot.addChild(pl);
	
        //create keyboard navigation behavior
                ViewingPlatform plat= u.getViewingPlatform();
                KeyNavigatorBehavior walk= new KeyNavigatorBehavior(viewTrans);
                walk.setSchedulingBounds(bounds);
                objRoot.addChild(walk);
        	
        //reposition the view platform
                Transform3D viewTrans3D= new Transform3D();
                viewTrans.getTransform(viewTrans3D);
                viewTrans3D.rotX(-Math.PI/6);
                viewTrans3D.setTranslation(new Vector3d(0f, 8f, 20f));
                viewTrans.setTransform(viewTrans3D);

        //set back clipping distance	
                View v= c.getView();
                v.setBackClipDistance((double)30);
        	
        //fog
                ExponentialFog fog= new ExponentialFog(new Color3f(0f, 0f, 0f), .15f);
                fog.setInfluencingBounds(bounds);
                objRoot.addChild(fog);

        //animalRoot
                objRoot.addChild(animalRoot);

        //Have Java 3D perform optimizations on this scene graph.
//              objRoot.compile();

                return objRoot;
        }//createSceneGraph

/*
        setup
*/
        private void setUp(){
                int i, num;

        //set up sheep
                SHEEP_EAT= sheepEatScroll.getValue();
                SHEEP_AGE= sheepAgeScroll.getValue();
                SHEEP_REP= SHEEP_AGE/4;

                sheep= new Vector(2*sheepNumScroll.getValue(), 1);
                sheepBranch= new Vector(sheep.size(), 1);
//              sheepPos= new Vector(sheep.size(), 1);

                Sheep3D s, s2;
                for (i= 0, num= 2*sheepNumScroll.getValue(); i < num; i+= 2){
                        sheep.addElement(new Sheep3D(sheepTotalCount, sheepAppear));
                        sheep.addElement(new Sheep3D(sheepTotalCount+1, sheepAppear));
                        sheepTotalCount+= 2;
                	
                        BranchGroup b= buildBranchGroup(), b1= buildBranchGroup();
                        TransformGroup t= new TransformGroup(), t1= new TransformGroup();
                        Transform3D t3= new Transform3D(), t3d= new Transform3D();
                	
                        t3.setTranslation(new Vector3d((5-Math.random()*10), -initAnimalSize*SHEEP_SIZE/2, (5 - Math.random()*10)));
                        t3.get(((Sheep3D)sheep.elementAt(i)).position);
                        t3.setScale(initAnimalSize);
                        t.setTransform(t3);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        t.addChild(((Sheep3D)sheep.elementAt(i)).sphere);
                        b.addChild(t);
                	
                        t3d.setTranslation(new Vector3d((5-Math.random()*10), -initAnimalSize*SHEEP_SIZE/2, (5 - Math.random()*10)));
                        t3d.get(((Sheep3D)sheep.elementAt(i+1)).position);
                        t3d.setScale(initAnimalSize);
                        t1.setTransform(t3d);
                        t1.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        t1.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        t1.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        t1.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        t1.addChild(((Sheep3D)sheep.elementAt(i+1)).sphere);
                        b1.addChild(t1);

                        sheepBranch.addElement(b);
                        sheepBranch.addElement(b1);
                        animalRoot.addChild(b);
                        animalRoot.addChild(b1);

/*                      AnimalRotator ar= new AnimalRotator(buildBranchGroup(), buildBranchGroup()), ar1= new AnimalRotator(buildBranchGroup(), buildBranchGroup());
                        ar.trans3D.setTranslation(new Vector3d((5-Math.random()*10), -initAnimalSize*SHEEP_SIZE/2, (5 - Math.random()*10)));
                        ar.trans3D.get(((Sheep3D)sheep.elementAt(i)).position);
                        ar.local3D.setScale(initAnimalSize);
                        ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar.t.addChild(((Sheep3D)sheep.elementAt(i)).sphere);

                        ar1.trans3D.setTranslation(new Vector3d((5-Math.random()*10), -initAnimalSize*SHEEP_SIZE/2, (5-Math.random()*10)));
                        ar1.trans3D.get(((Sheep3D)sheep.elementAt(i+1)).position);
                        ar1.local3D.setScale(initAnimalSize);
                        ar1.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar1.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar1.t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar1.t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar1.t.addChild(((Sheep3D)sheep.elementAt(i+1)).sphere);

                //add position information	
                        Vector3f v= new Vector3f(), v1= new Vector3f();
                        Alpha alpha= createAlpha();

                        ar.trans3D.get(v);
                        PositionInterpolator p= new PositionInterpolator(alpha, ar.t, ar.trans3D, v.x, v.x + 5 - (float)Math.random()*10);
                        p.setSchedulingBounds(bounds);
                        ar.t.addChild(p);
                        sheepPos.addElement(p);

                        ar1.trans3D.get(v1);
                        PositionInterpolator p1= new PositionInterpolator(alpha, ar1.t, ar1.trans3D, v1.x, v1.x + 5 - (float)Math.random()*10);
                        p1.setSchedulingBounds(bounds);
                        ar1.t.addChild(p1);
                        sheepPos.addElement(p1);

                        sheepBranch.addElement(ar.localU);
                        sheepBranch.addElement(ar1.localU);
                        animalRoot.addChild(ar.localU);
                        animalRoot.addChild(ar1.localU);
*/
                        s= (Sheep3D)sheep.elementAt(i);                                       s2= (Sheep3D)sheep.elementAt(i+1);
                        s.reproduce= SHEEP_REP/2;                                                     s2.reproduce= SHEEP_REP/2;
                        s.generation= 1;                                                                                      s2.generation= 1;
                        s.sex= true;                                                                                                  s2.sex= false;
                        s.pack= (Math.random() > .5 ? true : false);  s2.pack= (Math.random() > .5 ? true : false);
                }//for (build sheep)

        //set up wolves
                WOLF_EAT= wolfEatScroll.getValue();
                WOLF_AGE= wolfAgeScroll.getValue();
                WOLF_REP= WOLF_AGE/4;

                wolf= new Vector(2*wolfNumScroll.getValue(), 1);
                wolfBranch= new Vector(wolf.size(), 1);
//              wolfPos= new Vector(wolf.size(), 1);

                Wolf3D w, w2, tempWolf;
                for (i= 0, num= 2*wolfNumScroll.getValue(); i < num; i+= 2){
                        wolf.addElement(new Wolf3D(wolfTotalCount, wolfAppear));
                        wolf.addElement(new Wolf3D(wolfTotalCount+1, wolfAppear));
                        wolfTotalCount+= 2;

                        BranchGroup b= buildBranchGroup(), b1= buildBranchGroup();
                        TransformGroup t= new TransformGroup(), t1= new TransformGroup();
                        Transform3D t3= new Transform3D(), t3d= new Transform3D();
                	
                        t3.setTranslation(new Vector3d((5-Math.random()*10), -initAnimalSize*WOLF_SIZE/2, (5 - Math.random()*10)));
                        t3.get(((Wolf3D)wolf.elementAt(i)).position);
                        t3.setScale(initAnimalSize);
                        t.setTransform(t3);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        t.addChild(((Wolf3D)wolf.elementAt(i)).box);
                        b.addChild(t);
                	
                        t3d.setTranslation(new Vector3d((5-Math.random()*10), -initAnimalSize*WOLF_SIZE/2, (5 - Math.random()*10)));
                        t3d.get(((Wolf3D)wolf.elementAt(i+1)).position);
                        t3d.setScale(initAnimalSize);
                        t1.setTransform(t3d);
                        t1.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        t1.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        t1.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        t1.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        t1.addChild(((Wolf3D)wolf.elementAt(i+1)).box);
                        b1.addChild(t1);

                        wolfBranch.addElement(b);
                        wolfBranch.addElement(b1);
                        animalRoot.addChild(b);
                        animalRoot.addChild(b1);

/*                      AnimalRotator ar= new AnimalRotator(buildBranchGroup(), buildBranchGroup()), ar1= new AnimalRotator(buildBranchGroup(), buildBranchGroup());
                        ar.trans3D.setTranslation(new Vector3d((5-Math.random()*10), -.5 + initAnimalSize*WOLF_SIZE/2, (5 - Math.random()*10)));
                        ar.trans3D.get(((Wolf3D)wolf.elementAt(i)).position);
                        ar.local3D.setScale(initAnimalSize);
                        ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar.t.addChild(((Wolf3D)wolf.elementAt(i)).box);

                        ar1.trans3D.setTranslation(new Vector3d((5-Math.random()*10), -.5 + initAnimalSize*WOLF_SIZE/2, (5-Math.random()*10)));
                        ar1.trans3D.get(((Wolf3D)wolf.elementAt(i+1)).position);
                        ar1.local3D.setScale(initAnimalSize);
                        ar1.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar1.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar1.t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar1.t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar1.t.addChild(((Wolf3D)wolf.elementAt(i+1)).box);

                //create wolf position information	
                        Vector3f v= new Vector3f(), v1= new Vector3f();
                        Alpha alpha= createAlpha();

                        ar.trans3D.get(v);
                        PositionInterpolator p= new PositionInterpolator(alpha, ar.t, ar.trans3D, v.x, v.x + 5 - (float)Math.random()*10);
                        p.setSchedulingBounds(bounds);
                        ar.t.addChild(p);
                        wolfPos.addElement(p);

                        ar1.trans3D.get(v1);
                        PositionInterpolator p1= new PositionInterpolator(alpha, ar1.t, ar1.trans3D, v1.x, v1.x + 5 - (float)Math.random()*10);
                        p1.setSchedulingBounds(bounds);
                        ar1.t.addChild(p1);
                        wolfPos.addElement(p1);

                        wolfBranch.addElement(ar.localU);
                        wolfBranch.addElement(ar1.localU);
                        animalRoot.addChild(ar.localU);
                        animalRoot.addChild(ar1.localU);
*/
                        w= (Wolf3D)wolf.elementAt(i);                                                 w2= (Wolf3D)wolf.elementAt(i+1);
                        w.reproduce= WOLF_REP/2;                                                              w2.reproduce= WOLF_REP/2;
                        w.generation= 1;                                                                                      w2.generation= 1;	
                        w.sex= true;                                                                                                  w2.sex= false;
                        w.pack= (Math.random() > .5 ? true : false); w2.pack= (Math.random() > .5 ? true : false);
                }//for (build wolves)

        //set up grass
                grass= new Vector(VECTOR_SIZE, 0);
                grassBranch= new Vector(grass.size(), 1);
//              grassPos= new Vector(VECTOR_SIZE, 0);
//              Alpha alpha= createAlpha();
                for (i= 0; i < VECTOR_SIZE; i++){
                        BranchGroup b= buildBranchGroup();
                        TransformGroup t= new TransformGroup();
                        Transform3D t3= new Transform3D();
                	
                        grass.addElement(new Grass3D(""+i, grassAppear));
                        t3.setTranslation(new Vector3d((5-Math.random()*10), -.5+GRASS_LENGTH/(4-((Grass3D)grass.elementAt(i)).length), (5 - Math.random()*10)));
                        t3.get(((Grass3D)grass.elementAt(i)).position);
                        ((Grass3D)grass.elementAt(i)).x= (int)((Grass3D)grass.elementAt(i)).position.x;
                        ((Grass3D)grass.elementAt(i)).z= (int)((Grass3D)grass.elementAt(i)).position.z;
                        t3.setScale(GRASS_LENGTH/(4-((Grass3D)grass.elementAt(i)).length));
                        t.setTransform(t3);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        t.addChild(((Grass3D)grass.elementAt(i)).cone);
                        b.addChild(t);

                        grassBranch.addElement(b);
                        animalRoot.addChild(b);

/*                      AnimalRotator ar= new AnimalRotator(buildBranchGroup(), buildBranchGroup());
                        ar.trans3D.setTranslation(new Vector3d((5-Math.random()*10), -.5 + GRASS_LENGTH/8, (5 - Math.random()*10)));
                        grass.addElement(new Grass3D(""+i, grassAppear, ar.trans3D));
                        ar.trans3D.get(((Grass3D)grass.elementAt(i)).position);
                        ar.local3D.setScale(GRASS_LENGTH/(4-((Grass3D)grass.elementAt(i)).length));
                        ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar.t.addChild(((Grass3D)grass.elementAt(i)).cone);

                        Vector3f v= new Vector3f();
                        ar.trans3D.get(v);
                        PositionInterpolator p= new PositionInterpolator(alpha, ar.t, ar.trans3D, v.x, v.x);
                        p.setSchedulingBounds(bounds);
                        ar.t.addChild(p);
                        grassPos.addElement(p);
                	
                        angle= Math.atan(grass(i).position.z/grass(i).position.x);
                        if (grass(i).position.x < 0)
                                angle+= Math.PI/2;
                        Transform3D t3d= p.getAxisOfTranslation();
                        t3d.rotY(angle);

                        grassBranch.addElement(ar.localU);
                        animalRoot.addChild(ar.localU);
*/              	
                }//for (building grass) 
        	
        //remove all text objects
                for (i= 0, num= txtTrans.numChildren(); i < num; i++){
                        txtTrans.removeChild(i);
                }//for	
        }//setUp
        
/*
        PredPrey3D init
*/
        public void init() {
                start();
        }//init

/*
        Constructor
*/	
        public PredPrey3D(){
                System.out.println("Constructing new PredPrey3D");
                setLayout(new BorderLayout());
                add("Center", c);

        //Create a simple scene and attach it to the virtual universe
                BranchGroup scene = createSceneGraph();
                u.addBranchGraph(scene);
        }//PredPrey3D

/*
        PredPrey3D Run method
*/
        public void run(){
                try{
                        done= false;
                        sheepCount= new Vector(1, 10);
                        wolfCount= new Vector(1, 10);
                        time= 0;
                        sheepTime= 0;
                        wolfTime= 0;
                        sheepCount.addElement(new Entry(2*sheepNumScroll.getValue(), 0));
                        wolfCount.addElement(new Entry(2*wolfNumScroll.getValue(), 0));
                        int oldSheepCount= ((Entry)sheepCount.elementAt(0)).num, oldWolfCount= ((Entry)wolfCount.elementAt(0)).num;
                        int loop= 0;

                //main program loop	
                        while (!done){
                                numSheepAlive= sheep.size();
                                numWolfAlive= wolf.size();
        	
                        //test to see if there are still live animals of both classes	
                                if (numSheepAlive == 0 || numWolfAlive == 0){
                                        done= true;
                                        for (int i= 0, num= txtTrans.numChildren(); i < num; i++){
                                                txtTrans.removeChild(i);
                                        }//for	
                                        Text3D txt;
                                        if (numWolfAlive == 0){
                                                txt= new Text3D(f3d, "All wolves died", new Point3f(-3f, 2f, -12f));
                                                System.out.println("All of wolf class died");
                                        }
                                        else{
                                                txt= new Text3D(f3d, "All sheep died", new Point3f(-3f, 2f, -12f));
                                                System.out.println("All of sheep class died");
                                        }
                                        Shape3D shape= new Shape3D();
                                        Appearance app= new Appearance();
                                        Material mat= new Material();
                                        app.setMaterial(mat);
                                        shape.setGeometry(txt);
                                        shape.setAppearance(app);
                                        BranchGroup btext= buildBranchGroup();
                                        btext.addChild(shape);
                                        txtTrans.addChild(btext);
                                        break;
                                }//if (animals died)

                                if (oldSheepCount != numSheepAlive)
                                        sheepCount.addElement(new Entry(numSheepAlive, time));
                                if (oldWolfCount != numWolfAlive)
                                        wolfCount.addElement(new Entry(numWolfAlive, time));
                                	
                                oldSheepCount= numSheepAlive;
                                oldWolfCount= numWolfAlive;
                                time++;
                                if (time%10 == 0)
                                        System.out.println("Time: "+ time);

                        //move sheep and wolves
                                moveSheep();
                                moveWolves();
                        	
                        //grow the grass
                                for (int i= 0; i < amountGrass; i++){
                                        tempGrass= grass(i);
                                        if (tempGrass.time >= 50){
                                                if (tempGrass.length < 3){
                                                        tempGrass.length++;
                                                        trans3D(i, GRASS).get(grassLoc);
                                                        grassLoc.y= -.5+(GRASS_LENGTH/(4-((Grass3D)grass.elementAt(i)).length))/2;
                                                        trans3D(i, GRASS).setScale(GRASS_LENGTH/(4-tempGrass.length));
                                                        trans3D(i, GRASS).setTranslation(grassLoc);
                                                        trans(i, GRASS).setTransform(trans3D(i, GRASS));
                                                        tempGrass.time= 0;
//                                                      System.out.println("grass: "+ tempGrass.name +" grew to "+ tempGrass.length);
                                                }
                                                else{
                                                        if (tempGrass.time > 200)
                                                                addGrass(tempGrass);
                                                        else
                                                                tempGrass.time++;       	
                                                }
                                        }//if (time to grow)
                                        else{
                                                tempGrass.time++;
                                        }
                                }//for (handle all grass)
                                try{
                                        runner.sleep(500);
                                }//try
                                catch(InterruptedException e){
                                        System.out.println("sleep interrupted: " +e.toString());
                                }//catch (sleep)
                                runner.yield();
                        }//while (!done)
                }//try
                catch(NullPointerException e){
                        System.out.println("Error in run: " + e.toString());
                        throw e;
                }//catch
                System.out.println("after while loop");
        }//run

//moveSheep
        private void moveSheep(){
                for (int a= 0; a < sheep.size(); a++){
                        sheepSize= sheep.size();
                        Sheep3D s= sheep(a);
                        s.age++;
                        s.eat++;
                        s.reproduce++;

                        if (s.eat > SHEEP_EAT || s.age > SHEEP_AGE){
/*                              for (int i= 0, num= animalRoot.numChildren(); i < num; i++){
                                        if (((BranchGroup)sheepBranch.elementAt(a)) == animalRoot.getChild(i)){
                                                System.out.println("sheep "+ s.name +" died");
//                                              animalRoot.removeChild(i);
                                                break;
                                        }//if
                                }//for i
*/
System.out.println("Removing dead sheep "+ s.name);
                                ((BranchGroup)sheepBranch.elementAt(a)).detach();
                                sheepBranch.removeElementAt(a);
                                sheep.removeElementAt(a);
                                continue;
                        }//if sheep died

                //resize and position accordingly
//                      ((BranchGroup)sheepBranch.elementAt(a)).detach();
                        Transform3D t3= trans3D(a, SHEEP);
                        t3.setScale(((s.age+SHEEP_AGE/3)/100 < 1 ? (s.age+SHEEP_AGE/3)/100 : 1));
                        s.position.y= (float)(-.5+trans3D(a, SHEEP).getScale()/2);

                //move randomly
                        s.position.x+= (float)(1 - 2*Math.random());
                        s.position.z+= (float)(1 - 2*Math.random());

//System.out.println("sheep "+ s.name +" "+ s.position.toString());
                        t3.setTranslation(s.position);
                        trans(a, SHEEP).setTransform(t3);
//                      animalRoot.addChild((BranchGroup)sheepBranch.elementAt(a));

/*                      angle= Math.atan(s.position.z/s.position.x);
                        if (s.position.x < 0)
                                angle+= Math.PI/2;
                        PositionInterpolator p= (PositionInterpolator)sheepPos.elementAt(a);
                        Transform3D t3d= p.getAxisOfTranslation();
                        t3d.rotY(angle);
                        p.setStartPosition(p.getEndPosition() + (float)Math.sqrt(s.position.x*s.position.x + s.position.z*s.position.z));
*/
/*                      if (s.reproduce > SHEEP_REP){
                                s.rep= true;
                                trans3D(a, SHEEP).get(s.position);                              	
                                s.x= (int)s.position.x;
                                s.z= (int)s.position.z;
                                for (int i= 0; i < sheepSize; i++){
                                        tempSheep= sheep(i);
                                        tempDist= dist(s, tempSheep);
                                        if (tempDist == -1){
                                                s= new Sheep3D(sheepTotalCount, sheepAppear);                                 	
                                        }
                                        else if (tempDist == -2){
                                                tempSheep= new Sheep3D(sheepTotalCount, sheepAppear);                                 	
                                        }
                                        if (tempSheep.sex != s.sex && tempSheep.rep && tempDist <= 3*sheepSight/2){
                                                s.mate= i;
                                                tempSheep.mate= a;
                                        }//if
                                }//for (all other sheep)
                        }//if (can reproduce)
                        else{
                                s.rep= false;
                        }//else (can't reproduce)
                        if (s.eat > 0){
                                for (int i=0; i < VECTOR_SIZE; i++){
                                        tempGrass= grass(i);
                                        tempDist= dist(tempGrass, s);
                                        if (tempDist == -1){
                                                TransformGroup tg= new TransformGroup();
                                                Transform3D t3= new Transform3D();
                                                tg.getTransform(t3);            	
                                                t3.setTranslation(new Vector3d((float)(width/2-Math.random()*width), 1f, (float)(length/2-Math.random()*length)));
                                                t3.setScale(.3);
                                                tempGrass= new Grass3D(""+i, grassAppear, t3);
                                        }
                                        else if (tempDist == -2){
                                                tempSheep= new Sheep3D(sheepTotalCount, sheepAppear);                                 	
                                        }
                                        if (tempGrass.length > 0 && dist(tempGrass, s) <= 10){
                                                s.eat= -100;
                                                s.seeGrass= false;
                                                tempGrass.length--;
                                                if (s.mem[(int)(s.x/width)][(int)(s.z/length)] < MAX_MEM)
                                                        s.mem[(int)(s.x/width)][(int)(s.z/length)]+= 10;
                                                break;
                                        }//if (within 10 of grass)
                                        else if (tempGrass.length > 0 && dist(tempGrass, s) < sheepSight + 25){
                                                distance= 500;                        	
                                                double temp;
                                                temp= dist(tempGrass, s);
                                                if (temp < distance){
                                                        distance= temp;
                                                        s.seeGrass= true;
                                                        s.grassX= tempGrass.x;
                                                        s.grassZ= tempGrass.z;
                                                        if (s.mem[s.x/width][s.z/length] < MAX_MEM)
                                                                s.mem[s.x/width][s.z/length]+= 1;
                                                }//if
                                        }//else (look for grass)
                                }//for (all grass)
                        }//if (eat > 0)
                        wolfSize= wolf.size();
                        for (int i=0; i < wolfSize; i++){
                                tempWolf= wolf(i);
                                if (dist(s, tempWolf) <= sheepSight){
                                        s.seeWolf= true;
                                        s.wolfX= tempWolf.x;
                                        s.wolfZ= tempWolf.z;
                                        break;
                                }//if (see wolf)
                        }//for (all wolves)
                        int temp, xp= s.x/width, zp= s.z/length;
                        if ((s.memory++ % 15) == 0){
                                for (int i= 0; i < 10; i++){
                                        for (int j= 0; j < 10; j++){
                                                if (s.mem[i][j] < 0)
                                                s.mem[i][j]+= 1;
                                                else if (s.mem[i][j] > 0)
                                                s.mem[i][j]-= 1;
                                        }//for (j)
                                }//for (i)
                        }//if (time to change mem)
                        if ((xp == 0 && (zp == 0 || zp >= 9)) || (xp >= 9 && (zp == 0 || zp >= 9))){
                                sheepMoveMem(s);
                        }
                        else if (s.mate != a){
                                tempSheep= sheep(s.mate);
                                if (dist(s, tempSheep) <= 10){
                                        if (s.mem[s.x/width][s.z/length] < MAX_MEM)
                                                s.mem[s.x/width][s.z/length]+= 20;
                                        if (tempSheep.mem[tempSheep.x/width][tempSheep.z/length] < MAX_MEM)
                                                tempSheep.mem[tempSheep.x/width][tempSheep.z/length]+= 20;
                                        tempSheep.mate= s.mate;
                                        addSheep(s, sheep(s.mate));
                                        s.mate= a;
                                }
                                else {
                                        temp= s.x - tempSheep.x;
                                        s.x-= 5 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                        temp= s.z - tempSheep.z;
                                        s.z-= 5 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                }
                        }// if (mate is not same as self)
                        else if (s.seeWolf){
                                s.mem[s.x/width][s.z/length]-= 2;
                                if (s.pack && countSheep(s) > 1){
                                        int oldest= a;
                                        for (int i= 0; i < sheepSize; i++){
                                                tempSheep= sheep(i);
                                                if (dist(s, tempSheep) <= sheepSight && tempSheep.age > s.age){
                                                        s.oldest= i;
                                                }
                                        }
                                        if (s.oldest != a){
                                                temp= s.x - sheep(oldest).x;
                                                s.x-= 7 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                                temp= s.z - sheep(oldest).z;
                                                s.z-= 7 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                        }//if (s is not oldest)
                                        else{
                                                temp= s.x - s.wolfX;
                                                s.x+= 7 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                                temp= s.z - s.wolfZ;
                                                s.z+= 7 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                        }//else (just run away)
                                }  // if (s.pack && countSheep(i) > 1)
                                else{
                                        temp= s.x - s.wolfX;
                                        s.x+= 7 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                        temp= s.z - s.wolfZ;
                                        s.z+= 7 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                }//see wolf (run away)
                                s.seeWolf= false;
                        }  // if (seeWolf)
                        else if (s.seeGrass){
                                temp= s.x - s.grassX;
                                s.x-= 5 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                temp= s.z - s.grassZ;
                                s.z-= 5 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                s.seeGrass= false;
                        }// if (seeGrass)
                        else{
                                int count= countSheep(s);
                                if ((s.move++ % 5) == 0){
                                        if (s.mem[s.x/width][s.z/length] > MIN_MEM)
                                                s.mem[s.x/width][s.z/length]-= 2;
                                        s.moveX= 5 - (int)(Math.random() * 10);
                                        s.moveZ= 5 - (int)(Math.random() * 10);
                                        if (s.mem[s.x/width][s.z/length] < 0)
                                                sheepMoveMem(s);
                                        else if (Math.random() < .5)
                                                sheepMoveMem(s);
                                }//if (time to pick new dir)
                                s.x+= s.moveX;
                                if (s.pack){
                                        if (countSheep(s) < count)
                                        s.x-= 2*s.moveX;
                                }
                                s.z+= s.moveZ;
                                if (s.pack){
                                        if (countSheep(s) < count)
                                        s.z-= 2*s.moveZ;
                                }
                        }//move randomly
                        if (s.x < -width/2)
                                s.x= -width/2;
                        else if (s.x > width/2)
                                s.x= width/2;
                        if (s.z < -length/2)
                                s.z= -length/2;
                        else if (s.z > length/2)
                                s.z= length/2;
        	
                        s.position.x= s.x;
                        s.position.z= s.z;
                        trans3D(a, SHEEP).setTranslation(s.position);
*/
                }//for (all sheep)
        }//moveSheep
	
//sheepMoveMem
        private void sheepMoveMem(Sheep3D s){
                double dir[]= new double[4];
                int squares, i, j, currX= s.x/length, currZ= s.z/length;
                for (i= 0, squares= 0, dir[0]= 0; i < 10; i++){
                        for (j= 0; j < currZ; j++){
                                squares++;
                                dir[0]+= s.mem[i][j];
                        }
                }
                dir[0]/= (squares != 0 ? squares : 1);
                for (i= 0, squares= 0, dir[1]= 0; i < 10; i++){
                        for (j= currZ + 1; j < 10; j++){
                                squares++;
                                dir[1]+= s.mem[i][j];
                        }
                }
                dir[1]/= (squares != 0 ? squares : 1);
                if (dir[0] != dir[1])
                        s.moveZ+= 10 * Math.random() * (dir[0] > dir[1] ? -1 : 1);
                else
                        s.moveZ+= 10 * Math.random() * (Math.random() > .5 ? 1 : -1);
                for (j= 0, squares= 0, dir[2]= 0; j < 10; j++){
                        for (i=  0; i < currZ; i++){
                                squares++;
                                dir[2]+= s.mem[i][j];
                        }
                }
                dir[2]/= (squares != 0 ? squares : 1);
                for (j= 0, squares= 0, dir[3]= 0; j < 10; j++){
                        for (i= currX + 1; i < 0; i++){
                                squares++;
                                dir[3]+= s.mem[i][j];
                        }
                }
                dir[3]/= (squares != 0 ? squares : 1);
                if (dir[2] != dir[3]){
                        s.moveX+= 10 * Math.random() * (dir[2] > dir[3] ? -1 : 1);
                }
                else{
                        s.moveX+= 10 * Math.random() * (Math.random() > .5 ? 1 : -1);
                }

                s.x+= s.moveX;
                s.z+= s.moveZ;
        }//sheepMoveMem
	
        //addSheep
        public void addSheep(Sheep3D f, Sheep3D m){
                if (sheep.size() < 100){
                        int firstFree= -1;
                        f.reproduce= SHEEP_REP/2;
                        f.rep= false;
                        m.reproduce= SHEEP_REP/2;
                        m.rep= false;
                        Sheep3D s= new Sheep3D(sheepTotalCount, f.appear);
                        sheepTotalCount++;
                        s.x= f.x;
                        s.z= f.z;
                        s.generation= (f.generation > m.generation ? f.generation : m.generation) + 1;
                        if (f.pack && m.pack)
                                s.pack= true;
                        else if (!f.pack && !m.pack)
                                s.pack= false;
                        else{
                                s.pack= (Math.random() > .5 ? true : false);
                        }
                        for (int k= 0; k < 10; k++){
                                for (int j= 0; j < 10; j++){
                                        s.mem[k][j]= (int)((f.mem[k][j] + m.mem[k][j])/2);
                                }
                        }
                        sheep.addElement(s);
                }//if (sheep.size() < 100)
        }//addSheep
	
//count sheep
        private int countSheep(Sheep3D s){
                int shp= 0;
                try{
                        if (s != null){
                                for (int j= 0; j < sheep.size(); j++){
                                        tempSheep= sheep(j);
                                        if (dist(s, tempSheep) <= sheepSight){
                                                shp++;
                                        }
                                }//for (all sheep)
                        }//if (s != null)
                }//try
                catch(NullPointerException e){
                        System.out.println("error in countSheep: " + e.toString());
                }
                return shp;
        }//countSheep

        //sheepWarn
        public void sheepWarn(Sheep3D s){
                int xs, zs;
                for (int j= 0; j < sheep.size(); j++){
                        tempSheep= sheep(j);
                        if (dist(s, tempSheep) <= (sheepSight + 20)){
                                xs= s.x/width;
                                zs= s.z/length;
                                if (tempSheep.mem[xs][zs] > MIN_MEM)
                                        tempSheep.mem[xs][zs]-= 30;
                        }//if
                }//for
        	
//make other sheep see wolf

        }//sheepWarn
	
//moveWolves
        private void moveWolves(){
                for (int a= 0; a < wolf.size(); a++){
                        wolfSize= wolf.size();
                        Wolf3D w= wolf(a);
                        w.age++;
                        w.reproduce++;
                        w.eat++;
                        w.seeSheep= false;
                        if (w.eat > WOLF_EAT || w.age > WOLF_AGE){
                                for (int i= 0, num= animalRoot.numChildren(); i < num; i++){
                                        if (((BranchGroup)wolfBranch.elementAt(a)) == animalRoot.getChild(i)){
                                                System.out.println("wolf"+ w.name +" died");
                                                animalRoot.removeChild(i);
                                                break;
                                        }//if
                                }//for i
                                wolfBranch.removeElementAt(a);
                                wolf.removeElementAt(a);
                                continue;
                        }//if wolf died

                //resize and position accordingly
                        Transform3D t3= trans3D(a, WOLF);
                        t3.setScale(((w.age+WOLF_AGE/3)/100 < 1 ? (w.age+WOLF_AGE/3)/100 : 1));
                        w.position.y= (float)(-.5+trans3D(a, WOLF).getScale()/2);
                        t3.setTranslation(w.position);
                	
                //move randomly
                        w.position.x+= (float)(.02 - .04*Math.random());
                        w.position.z+= (float)(.02 - .04*Math.random());

                        t3.setTranslation(w.position);
                        angle= Math.atan(w.position.z/w.position.x);
                        if (w.position.x < 0)
                                angle+= Math.PI/2;
                        t3.rotY(angle);
                        trans(a, WOLF).setTransform(t3);
                	
/*                      PositionInterpolator p= (PositionInterpolator)wolfPos.elementAt(a);
                        Transform3D t3d= p.getAxisOfTranslation();
                        t3d.rotY(angle);
                        p.setStartPosition(p.getEndPosition() + (float)Math.sqrt(w.position.x*w.position.x + w.position.z*w.position.z));
*/
/*                      if (w.reproduce > WOLF_REP){
                                for (int i= 0; i < wolfSize; i++){
                                        tempWolf= wolf(i);
                                        tempDist= dist(w, tempWolf);
                                        if (w.sex != tempWolf.sex && tempWolf.rep && tempDist <= 3/2*wolfSight){
                                                w.mate= i;
                                                tempWolf.mate= a;
                                        }//if
                                }//for
                        }//if
                        else{
                                w.rep= false;
                        }
                        if (w.eat > 0){
                                int wolves= countWolf(w);
                                if (w.seeSheep){
                                        for (int i= 0; i < sheep.size(); i++){
                                                tempSheep= sheep(i);
                                                if (dist(tempSheep, w) <= 10 && countSheep(tempSheep) <= 2*wolves){
                                                        sheepWarn(tempSheep);
                                                        sheep.removeElementAt(i);
                                                        w.eat= -75;
                                                        w.attack= false;
                                                        w.seeSheep= false;
                                                        w.rep= true;
                                                        w.mem[w.x/width][w.z/length]+= 20;
                                                } //if
                                        }//for
                                }//if (seeSheep)
                                else{
                                        double temp= 1000;
                                        for (int i= 0; i < sheep.size(); i++){
                                                tempSheep= sheep(i);
                                                tempDist= dist(tempSheep, w);
                                                if (tempDist <= wolfSight){
                                                        if (w.mem[w.x/width][w.z/length] < MAX_MEM)
                                                                w.mem[w.x/width][w.z/length]+= 2;
                                                        w.shp= countSheep(tempSheep);
                                                        if (tempDist < temp && 2*wolves >= w.shp){
                                                                temp= tempDist;
                                                                tempSheep= sheep(i);
                                                                w.sheepName= tempSheep.getName();
                                                                w.shp= i;
                                                                w.sheepX= tempSheep.x;
                                                                w.sheepZ= tempSheep.z;
                                                                w.seeSheep= true;
                                                                if (w.pack){
                                                                        for (int j= 0; j < wolfSize; j++){
                                                                                tempWolf= wolf(j);
                                                                                if (tempWolf.pack && tempWolf.eat > 0    && !tempWolf.seeSheep && dist(w, tempWolf) <= wolfSight){
                                                                                        if (tempWolf.mem[tempWolf.x/width][tempWolf.z/length] < MAX_MEM)
                                                                                                tempWolf.mem[tempWolf.x/width][tempWolf.z/length]+= 2;
                                                                                        tempWolf.seeSheep= true;
                                                                                        tempWolf.seeSheep= w.seeSheep;
                                                                                        tempWolf.sheepX= tempSheep.x;
                                                                                        tempWolf.sheepZ= tempSheep.z;
                                                                                }//if (add to mem)
                                                                        }//for (wolf in sight)
                                                                }//if (pack)
                                                                break;
                                                        }//if (2*wolf >= sheep)
                                                        else{
                                                                w.seeSheep= false;
                                                        }//else
                                                } //if (sheep is in range)
                                        }//for (all sheep)
                                } //if (!attack)
                                if (w.sheepName != null && !w.sheepName.equals(sheep(w.shp).getName())){
                                        w.seeSheep= false;
                                }//if (names don't match)
                                else if (w.seeSheep && w.pack){
                                        for (int i= 0; i < wolfSize; i++){
                                                tempWolf= wolf(i);
                                                if (tempWolf.pack && dist(w, tempWolf) < wolfSight && !tempWolf.seeSheep){
                                                        tempWolf.seeSheep= true;
                                                        tempWolf.seeSheep= w.seeSheep;
                                                        tempWolf.sheepX= w.sheepX;
                                                        tempWolf.sheepZ= w.sheepZ;
                                                }
                                        }//for (all wolves)
                                }// if (seeSheep)
                        }//if (eat >= 0)
                        int temp;
                        if ((w.memory++ % 15) == 0){
                                for (int i= 0; i < 10; i++){
                                        for (int j= 0; j < 10; j++){
                                                if (w.mem[i][j] < 0)
                                                w.mem[i][j]+= 1;
                                                if (w.mem[i][j] > 0)
                                                w.mem[i][j]-= 1;
                                        }
                                }//for (add to mem)
                        }//if (time to change mem)
                        if (w.mate != a){
                                tempWolf= wolf(w.mate);
                                if (dist(w, tempWolf) < 20){
                                        if (w.mem[w.x/width][w.z/length] < MAX_MEM)
                                                w.mem[w.x/width][w.z/length]+= 20;
                                        if (tempWolf.mem[tempWolf.x/width][tempWolf.z/length] < MAX_MEM)
                                                tempWolf.mem[tempWolf.x/width][tempWolf.z/length]+= 20;
                                        tempWolf.mate= w.mate;
                                        tempWolf.reproduce= 0;
                                        w.reproduce= 0;
                                        addWolf(w);
                                        w.mate= a;
                                }//if (mate is within range)
                                else {
                                        temp= w.x - tempWolf.x;
                                        w.x-= 10 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                        temp= w.z - tempWolf.z;
                                        w.z-= 10 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                }
                        }//if (mating)
                        else if (w.seeSheep){
                                temp= w.x - w.sheepX;
                                w.x-= 10 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                                temp= w.z - w.sheepZ;
                                w.z-= 10 * (int)(temp)/((temp != 0 ? Math.abs(temp) : 1));
                        }//if (seeSheep)
                        else{
                                int count= countWolf(w);
                                if ((w.move++ %5) == 0){
                                        w.mem[w.x/width][w.z/length]-= 2;
                                        w.moveX= 10 - (int)(Math.random() * 20);
                                        w.moveZ= 10 - (int)(Math.random() * 20);
                                        if (w.mem[w.x/width][w.z/length] < 0)
                                                wolfMoveMem(w);
                                        else if (Math.random() > .5){
                                                wolfMoveMem(w);
                                        }
                                }
                                w.x+= w.moveX;
                                if (w.pack && countWolf(w) < count-.8*wolfSize){
                                        w.x-= 2*w.moveX;
                                }
                                w.z+= w.moveZ;
                                if (w.pack && countWolf(w) < count-.8*wolfSize){
                                        w.z-= 2*w.moveZ;
                                }
                        }//else (move random)
                        if (w.x < -width/2)
                                w.x= -width/2;
                        else if (w.x > width/2 - 10)
                                w.x= width/2 - 10;
                        if (w.z < -length/2)
                                w.z= -length/2;
                        else if (w.z > length/2 - 10)
                                w.z= length/2 - 10;
*/
                }//for (all wolves)
        }//moveWolves

        //wolfMoveMem
        private void wolfMoveMem(Wolf3D w){
                double dir[]= new double[4];
                int squares, i, j;
                for (i= 0, squares= 0, dir[0]= 0; i < 10; i++){
                        for (j= 0; j < w.z/length; j++){
                                squares++;
                                dir[0]+= w.mem[i][j];
                        }
                }
                dir[0]/= (squares != 0 ? squares : 1);
                for (i= 0, squares= 0, dir[1]= 0; i < 10; i++){
                        for (j= w.z/length + 1; j < 10; j++){
                                squares++;
                                dir[1]+= w.mem[i][j];
                        }
                }
                dir[1]/= (squares != 0 ? squares : 1);
                if (dir[0] != dir[1])
                        w.moveZ+= 10 * Math.random() * (dir[0] > dir[1] ? -1 : 1);
                else
                        w.moveZ+= 10 * Math.random() * (Math.random() > .5 ? 1 : -1);
                for (j= 0, squares= 0, dir[2]= 0; j < 10; j++){
                        for (i=  0; i < w.x/width; i++){
                                squares++;
                                dir[2]+= w.mem[i][j];
                        }
                }
                dir[2]/= (squares != 0 ? squares : 1);
                for (j= 0, squares= 0, dir[3]= 0; j < 10; j++){
                        for (i= w.x/width + 1; i < 0; i++){
                                squares++;
                                dir[3]+= w.mem[i][j];
                        }
                }
                dir[3]/= (squares != 0 ? squares : 1);
                if (dir[2] != dir[3])
                        w.moveX+= 10 * Math.random() * (dir[2] > dir[3] ? -1 : 1);
                else
                        w.moveX+= 10 * Math.random() * (Math.random() > .5 ? 1 : -1);

                w.x+= w.moveX;
                w.z+= w.moveZ;
        }//wolfMoveMem

//addWolf
        public void addWolf(Wolf3D w){
                if (wolf.size() < 100){
                        Wolf3D nw= new Wolf3D(wolf.size(), w.appear);
                        nw.x= w.x;
                        nw.z= w.z;
                        tempWolf= wolf(w.mate);
                        nw.generation= (w.generation > tempWolf.generation ? w.generation : tempWolf.generation) + 1;
                        if (w.pack && tempWolf.pack)
                                nw.pack= true;
                        else if (!w.pack && !tempWolf.pack)
                                nw.pack= false;
                        else{
                                double temp= Math.random();
                                nw.pack= (temp > .5 ? true : false);
                        }
                        wolf.addElement(nw);
                                TransformGroup tg= new TransformGroup();
                                Transform3D     t3= new Transform3D();
                                tg.getTransform(t3);
                                t3.setScale(initAnimalSize);
                                tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                                tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                                tg.addChild(nw.box);
                }//if (wolf.size() < 100)
        }//addWolf

//count wolf
        public int countWolf(Wolf3D w){
                int wlf= 1;
                wolfSize= wolf.size();
                for (int i= 0; i < wolfSize; i++){
                        if (dist(w, wolf(i)) <= wolfSight){
                                wlf++;
                        }
                }
                return wlf;
        }//countWolf

//add grass
        private void addGrass(Grass3D parent){
System.out.println("added grass");	
                BranchGroup b= buildBranchGroup();
                TransformGroup t= new TransformGroup();
                Transform3D t3= new Transform3D();
        	
                t3.setTranslation(new Vector3d((5-Math.random()*10), -GRASS_LENGTH/8, (5 - Math.random()*10)));
                t3.get(((Grass3D)grass.elementAt(grass.size() - 1)).position);
                t3.setScale(GRASS_LENGTH/(4-((Grass3D)grass.elementAt(grass.size() - 1)).length));
                t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                t.addChild(((Grass3D)grass.elementAt(grass.size() - 1)).cone);
                b.addChild(t);

                grassBranch.addElement(b);
                animalRoot.addChild(b);

/*              AnimalRotator ar= new AnimalRotator(buildBranchGroup(), buildBranchGroup());
                ar.trans3D.setTranslation(new Vector3d(parent.position.x + (.5-Math.random()), -.5 + GRASS_LENGTH/8, parent.position.z + (.5 - Math.random())));
                grass.addElement(new Grass3D(""+ grass.size(), grassAppear, ar.trans3D));
                ar.trans3D.get(((Grass3D)grass.elementAt(grass.size() - 1)).position);
                ar.local3D.setScale(GRASS_LENGTH/(4-((Grass3D)grass.elementAt(grass.size() - 1)).length));
                ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                ar.t.addChild(((Grass3D)grass.elementAt(grass.size() - 1)).cone);

                Vector3f v= new Vector3f();
                ar.trans3D.get(v);
                Alpha alpha= createAlpha();
                PositionInterpolator p= new PositionInterpolator(alpha, ar.t, ar.trans3D, v.x, v.x);
                p.setSchedulingBounds(bounds);
                ar.t.addChild(p);
//              grassPos.addElement(p);
        	
                angle= Math.atan(grass(grass.size() - 1).position.z/grass(grass.size() - 1).position.x);
                if (grass(grass.size() - 1).position.x < 0)
                        angle+= Math.PI/2;
                Transform3D t3d= p.getAxisOfTranslation();
                t3d.rotY(angle);

                grassBranch.addElement(ar.localU);
                animalRoot.addChild(ar.localU);
*/
        }//add grass
	
//dist method
        public double dist(Animal a, Animal b){
                try{
                        return java.lang.Math.sqrt(java.lang.Math.pow((a.x - b.x), 2) + java.lang.Math.pow((a.z - b.z), 2));
                }
                catch(NullPointerException e){
                        if (a == null){
                                System.out.println("a was Null. b was: " +b.toString());
                                return -1.0;
                        }
                        else if (b == null){
                                System.out.println("b was Null. a was: " +a.toString());
                                return -2.0;
                        }
                        else{
                                System.out.println("not real sure what it was");
                                return -1.0;
                        }
                }
        }//dist

//sheep
        private Sheep3D sheep(int i){
                if (i < sheep.size())
                        return (Sheep3D)sheep.elementAt(i);
                else{
System.out.println("***something screwed up and have to create new sheep in sheep(int)***");
                        Sheep3D s= new Sheep3D(sheepTotalCount, sheepAppear);
                        sheep.addElement(s);
                        sheepTotalCount= sheep.size();

                        AnimalRotator ar= new AnimalRotator(buildBranchGroup(), buildBranchGroup());
                        ar.trans3D.setTranslation(new Vector3d((5-Math.random()*10), -initAnimalSize*SHEEP_SIZE/2, (5 - Math.random()*10)));
                        ar.trans3D.get(((Sheep3D)sheep.elementAt(i)).position);
                        ar.local3D.setScale(initAnimalSize);
                        ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar.t.addChild(((Sheep3D)sheep.elementAt(i)).sphere);
                        Vector3f v= new Vector3f();
                        Alpha alpha= createAlpha();
                        ar.trans3D.get(v);
                        PositionInterpolator p= new PositionInterpolator(alpha, ar.t, ar.trans3D, v.x, v.x + 5 - (float)Math.random()*10);
                        p.setSchedulingBounds(bounds);
                        ar.t.addChild(p);
//                      sheepPos.addElement(p);
                        sheepBranch.addElement(ar.localU);
                        animalRoot.addChild(ar.localU);

                        return s;
                }//else
        }//sheep

        private Wolf3D wolf(int i){
                if (i < wolf.size())
                        return (Wolf3D)wolf.elementAt(i);
                else{
System.out.println("***something screwed up and have to create new wolf in wolf(int)***");
                        Wolf3D w= new Wolf3D(wolfTotalCount, wolfAppear);
                        wolf.addElement(w);
                        wolfTotalCount= wolf.size();

                        AnimalRotator ar= new AnimalRotator(buildBranchGroup(), buildBranchGroup());
                        ar.trans3D.setTranslation(new Vector3d((5-Math.random()*10), -initAnimalSize*WOLF_SIZE/2, (5 - Math.random()*10)));
                        ar.trans3D.get(((Wolf3D)wolf.elementAt(i)).position);
                        ar.local3D.setScale(initAnimalSize);
                        ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar.localT.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                        ar.t.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                        ar.t.addChild(((Wolf3D)wolf.elementAt(i)).box);
                        Vector3f v= new Vector3f();
                        Alpha alpha= createAlpha();
                        ar.trans3D.get(v);
                        PositionInterpolator p= new PositionInterpolator(alpha, ar.t, ar.trans3D, v.x, v.x + 5 - (float)Math.random()*10);
                        p.setSchedulingBounds(bounds);
                        ar.t.addChild(p);
//                      wolfPos.addElement(p);
                        wolfBranch.addElement(ar.localU);
                        animalRoot.addChild(ar.localU);

                        return w;
                }//else
        }//wolf

        private Grass3D grass(int i){
                return (Grass3D)grass.elementAt(i);
        }//grass

        //PredPrey3D start method
        public void start(){
                if (runner == null){
                        runner= new Thread(this);
                }
                if (!runner.isAlive()){
                        runner.start();
                }
        }  //start

//trans
        private TransformGroup trans(int i, int type){
                TransformGroup t= new TransformGroup();
                try{
                        if (type == SHEEP && i < sheepBranch.size())
                                t= (TransformGroup)((BranchGroup)sheepBranch.elementAt(i)).getChild(0);
                        else if (type == WOLF && i < wolfBranch.size())
                                t= (TransformGroup)((BranchGroup)wolfBranch.elementAt(i)).getChild(0);
                        else if (i < grassBranch.size())
                                t= (TransformGroup)((BranchGroup)grassBranch.elementAt(i)).getChild(0);
                }
                catch(ArrayIndexOutOfBoundsException e){
                        System.out.println("type: "+ type +" error: "+ e.toString());
                }//catch
                finally{
                        return t;
                }
        }//trans (so you don't have to cast the vector each time)

//trans3D
        private Transform3D trans3D(int i, int type){
                Transform3D t3d= new Transform3D();
                if (type == SHEEP)
                        trans(i, SHEEP).getTransform(t3d);
                else if (type == WOLF)
                        trans(i, WOLF).getTransform(t3d);
                else
                        trans(i, GRASS).getTransform(t3d);
                return t3d;
        }//trans (so you don't have to cast the vector each time)

//buildBranchGroup
        private BranchGroup buildBranchGroup(){
                BranchGroup branch= new BranchGroup();
                branch.setCapability(BranchGroup.ALLOW_DETACH);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
                return branch;
        }//buildBranchGroup
	
//createAlpha
        private Alpha createAlpha(){
                return new Alpha(3,                                                                             /*loop count*/
                                                                        Alpha.INCREASING_ENABLE,
                                                                        0,                                                                              /*triggerTime*/
                                                                        0,                                                                              /*phaseDelayDuration*/
                                                                        1000,                                                                   /*increasingAlphaDuration*/
                                                                        500,                                                                    /*increasingAlphaRampDuration*/
                                                                        0,                                                                              /*alphaAtOneDuration*/
                                                                        1000,                                                                   /*decreasingAlphaDuration*/
                                                                        500,                                                                      /*decreasingAlphaRampDuration*/
                                                                        0);                                                                             /*alphaAtZeroDuration*/
        }//createAlpha
	
/*
Add picking behavior to view memory maps of animals
put upside down semi-transparent yellow cone above animal being observed

        //mouse listener
        public void mouseMoved(MouseEvent e){
                int x= e.getX()+5, y= e.getY()+5;
                for (int i= 0; i < vars.arrayLength/2; i++){
                        if (vars.s[2*i].alive && Math.sqrt((x-(vars.s[2*i].x+5))*(x-(vars.s[2*i].x+5)) + (y-(vars.s[2*i].y+5))*(y-(vars.s[2*i].y+5))) < 15){
                                animal.setLocation(0, 2*i);
                        }
                        else if (vars.s[2*i+1].alive && Math.sqrt((x-(vars.s[2*i+1].x+5))*(x-(vars.s[2*i+1].x+5)) + (y-(vars.s[2*i+1].y+5))*(y-(vars.s[2*i+1].y+5))) < 15){
                                animal.setLocation(0, 2*i+1);
                        }
                        else if (vars.w[i].alive && Math.sqrt((x-(vars.w[i].x-5))*(x-(vars.w[i].x-5)) + (y-(vars.w[i].y-5))*(y-(vars.w[i].y-5))) < 15){
                                animal.setLocation(1, i);
                        }
                }//for
        }//mouseMoved

        public void mouseClicked(MouseEvent e){
                animal.setLocation(-1, 0);
        }
        public void mouseDragged(MouseEvent e){}
        public void mousePressed(MouseEvent e){}
        public void mouseReleased(MouseEvent e){}
        public void mouseEntered(MouseEvent e){}
        public void mouseExited(MouseEvent e){}
*/

        //adjustment listener
        public void adjustmentValueChanged(AdjustmentEvent e){
                Scrollbar s= (Scrollbar)e.getSource();
                Integer value= new Integer(s.getValue());
                if (s.equals(sheepNumScroll))
                        sheepNumText.setText(value.toString());
                else if (s.equals(sheepAgeScroll))
                        sheepAgeText.setText(value.toString());
                else if (s.equals(sheepEatScroll))
                        sheepEatText.setText(value.toString());
                else if (s.equals(wolfNumScroll))
                        wolfNumText.setText(value.toString());
                else if (s.equals(wolfAgeScroll))
                        wolfAgeText.setText(value.toString());
                else
                        wolfEatText.setText(value.toString());
        }
	
        //action listener
        public void actionPerformed(ActionEvent e){
                Object o= e.getSource();
                if (o instanceof Button){
                        if (o.equals(reset)){
                                done= true;
                                setScrollBar(sheepNumScroll, sheepNumText);
                                setScrollBar(sheepAgeScroll, sheepAgeText);
                                setScrollBar(sheepEatScroll, sheepEatText);
                                setScrollBar(wolfNumScroll, wolfNumText);
                                setScrollBar(wolfAgeScroll, wolfAgeText);
                                setScrollBar(wolfEatScroll, wolfEatText);

                                for (; animalRoot.numChildren() > 0;){
                                        animalRoot.removeChild(0);
                                }//for (remove all objects in animalRoot)

                                run();
                                return;
                        }
                        else if (o.equals(opt)){
                                if (options.isVisible())
                                        options.setVisible(false);
                                else{
                                        options.setVisible(true);
                                        options.setLocation(this.getLocation().x + 610, this.getLocation().y);
                                }
                        }
                        else if (o.equals(dispGraph)){
                                if (graph.isVisible())
                                graph.setVisible(false);
                                else
                                graph.setVisible(true);
                        }
                        else if (o.equals(hlp)){
                                if (help.isVisible())
                                        help.setVisible(false);
                                else
                                        help.setVisible(true);
                        }//help
                        else{
                                setVisible(false);
                                graph.dispose();
                                options.dispose();
                                done= true;
                                System.exit(0);
                        }
                }//button clicked
                else if (o instanceof TextField){
                        TextField t= (TextField)o;
                        Integer i= new Integer(t.getText());
                        int value= i.intValue();
                        if (t.equals(sheepNumText)){
                                setScrollBar(sheepNumScroll, sheepNumText);
                        }
                        else if (t.equals(sheepAgeText)){
                                setScrollBar(sheepAgeScroll, sheepAgeText);
                        }
                        else if (t.equals(sheepEatText)){
                                setScrollBar(sheepEatScroll, sheepEatText);
                        }
                        else if (t.equals(wolfNumText)){
                                setScrollBar(wolfNumScroll, wolfNumText);
                        }
                        else if (t.equals(wolfAgeText)){
                                setScrollBar(wolfAgeScroll, wolfAgeText);
                        }
                        else if (t.equals(wolfEatText)){
                                setScrollBar(wolfEatScroll, wolfEatText);
                        }
                }//textField
        }//action listener

//buildFrames
        private void buildFrames(){
                try{
                        graphImg= createImage(300, 240);
                        if (graphImg != null)
                                graphBuf= graphImg.getGraphics();
                        graphPan= new Panel();
                        if (graphPan != null)
                                graphG= graphPan.getGraphics();
                //create text fields
                        sheepNumText= new TextField((new Integer(sheepNumScroll.getValue())).toString()); 
                        sheepAgeText= new TextField((new Integer(sheepAgeScroll.getValue())).toString()); 
                        sheepEatText= new TextField((new Integer(sheepEatScroll.getValue())).toString());
                        wolfNumText= new TextField((new Integer(wolfNumScroll.getValue())).toString());
                        wolfAgeText= new TextField((new Integer(wolfAgeScroll.getValue())).toString()); 
                        wolfEatText= new TextField((new Integer(wolfEatScroll.getValue())).toString());
                //add listeners for scrollbars
                        sheepNumScroll.addAdjustmentListener(this); sheepAgeScroll.addAdjustmentListener(this);     sheepEatScroll.addAdjustmentListener(this); sheepNumText.addActionListener(this); sheepAgeText.addActionListener(this); sheepEatText.addActionListener(this);
                        wolfNumScroll.addAdjustmentListener(this);      wolfAgeScroll.addAdjustmentListener(this); wolfEatScroll.addAdjustmentListener(this); wolfNumText.addActionListener(this); wolfAgeText.addActionListener(this);    wolfEatText.addActionListener(this);
                //setup options
                        options.setLocation(this.getLocation().x + 610, this.getLocation().y);
                        options.addWindowListener(this);
                        options.setLayout(new GridLayout(7, 4));
                        options.setResizable(false);
                        options.add(new Label("SHEEP"));  options.add(new Label(""));                   options.add(new Label(""));             options.add(new Label("WOLVES"));
                        options.add(new Label("Pairs:")); options.add(new Label("1:10"));               options.add(new Label("Pairs:"));       options.add(new Label("1:5"));
                        options.add(sheepNumScroll);              options.add(sheepNumText);                    options.add(wolfNumScroll);             options.add(wolfNumText);
                        options.add(new Label("Age:"));   options.add(new Label("100:1000"));   options.add(new Label("Age:"));         options.add(new Label("100:1200"));
                        options.add(sheepAgeScroll);              options.add(sheepAgeText);                            options.add(wolfAgeScroll);             options.add(wolfAgeText);
                        options.add(new Label("Eat:"));   options.add(new Label("50:500"));     options.add(new Label("Eat:")); options.add(new Label("50:600"));
                        options.add(sheepEatScroll);              options.add(sheepEatText);                            options.add(wolfEatScroll);             options.add(wolfEatText);
                        options.pack();
                //setup bottom
                        bottom= new Panel();
                        bottom.setLayout(new GridLayout(1, 7));
                        reset= new Button("Reset");
                        exit= new Button("Exit");
                        opt= new Button("Options");
                        dispGraph= new Button("Graph");
                        hlp= new Button("Help");
                        reset.addActionListener(this);
                        exit.addActionListener(this);
                        opt.addActionListener(this);
                        dispGraph.addActionListener(this);
                        hlp.addActionListener(this);
                        bottom.add(reset);  bottom.add(new Label(""));  bottom.add(opt);  bottom.add(new Label(""));  bottom.add(dispGraph);  bottom.add(new Label(""));  bottom.add(hlp);  bottom.add(new Label(""));  bottom.add(exit);
                        add("South", bottom);
                //set up graph frame
                        graph.setSize(300, 271);
                        graph.setLocation(this.getLocation().x + 610, this.getLocation().y + options.getSize().height);
                        graph.setResizable(false);
                        graphScroll= new ScrollPane();
                        graphPan.setSize(400, 321);
                        graphScroll.add(graphPan);
                        graph.add(graphScroll);
                        graph.addWindowListener(this);
                //set up help frame
                        help.setSize(300, 200);
                        help.setLocation(this.getLocation().x + 610, this.getLocation().y + options.getSize().height + graph.getSize().height);
                        help.setResizable(false);
                        String nl= System.getProperty("line.separator");
                        helpText= new TextArea("Use the cursors to move in the scene"+ nl +"Use PgUp-PgDn to look up and down"+ nl +"Hold down Alt to move without turning");
                        helpText.setEditable(false);
                        help.add(helpText);
                        help.addWindowListener(this);
                }
                catch(NullPointerException e){
                        System.out.println("Error in buildFrame: " + e.toString());
                }
        }//buildFrames
	
//Window Listener
        public void windowOpened(WindowEvent e){}
        public void windowActivated(WindowEvent e){}
        public void windowDeactivated(WindowEvent e){}
        public void windowIconified(WindowEvent e){}
        public void windowDeiconified(WindowEvent e){}
        public void windowClosed(WindowEvent e){}
        public void windowClosing(WindowEvent e){
                if (e.getSource().equals(options))
                        options.setVisible(false);
                if (e.getSource().equals(help))
                        help.setVisible(false);
                else
                        graph.setVisible(false);
        }


//setScrollBar
        public void setScrollBar(Scrollbar s, TextField t){
                Integer i= new Integer(t.getText());
                int value= i.intValue();
                value= (value < s.getMaximum() ? value : s.getMaximum() - 1);
                value= (value > s.getMinimum() ? value : s.getMinimum());
                t.setText(new Integer(value).toString());
                s.setValue(value);
        }
	
//allow the program to be run as an application or applet
        public static void main(String[] args) {
                System.out.println("Running as an application");
                new MainFrame(new PredPrey3D(), 600, 600);
        }
}//class PredPrey3D

/*
Animal Class (sheep and wolf extend this)
*/
class Animal{
        int age, x, z, otherx, otherz, eat, mate, move, reproduce, generation, memory;
        Vector3f position, otherPos;
        int mem[][]= {{0}};
        double distance, moveX, moveZ;
        boolean alive, sex, pack, rep;
        Appearance appear;
        String name;
	
        public String getName(){
                return name;
        }//getName

        public Animal(String n){
                name= n;
                position= new Vector3f();
        }
	
        public String toString(){
                return (name);
        }//to string
}//class Animal

/*
Sheep3D class
*/
class Sheep3D extends Animal{
        int wolfX, wolfZ, grassX, grassZ, oldest;
        boolean seeWolf, seeGrass;
        Sphere sphere;

        //sheep constructor
        Sheep3D(int title, Appearance a){
                super ((""+title));
                mate= title;
                sex= (Math.random() >= .5 ? true : false);
                pack= (Math.random() >= .5 ? true : false);
                rep= false;
                age= eat= reproduce= wolfX= wolfZ= grassX= grassZ= move= memory= 0;
                sphere= new Sphere(1f, Sphere.GENERATE_TEXTURE_COORDS | Sphere.GENERATE_NORMALS, 20, a);
                mem= new int[10][10];
        }
}//class sheep

/*
Wolf3D class
*/
class Wolf3D extends Animal{
        int sheepX, sheepZ, shp, wolves, mate, move;
        boolean seeSheep, attack;
        String sheepName;
        Box box;
	
        //wolf constructor
        Wolf3D(int title, Appearance a){
                super ((""+title));
                mate= title;
                age= eat= move= sheepX= sheepZ= reproduce= 0;
                mem= new int[10][10];
                seeSheep= attack= alive= false;
                alive= false;
                rep= true;
                sex= (Math.random() >= .5 ? true : false);
                box= new Box(1f, 1f, 1f, Box.GENERATE_TEXTURE_COORDS | Box.GENERATE_NORMALS, a);
        }
}//wolf class


/*
Grass3D class
*/
class Grass3D extends Animal{
        int length, time;
        Cone cone;
	
        public Grass3D(String title, Appearance a/*, Transform3D trans*/){
                super (title);
                length= (int)(Math.random()*3);
                time= (int)(Math.random()*50);
                appear= (Appearance)a.cloneNodeComponent();
                appear.setCapability(Appearance.ALLOW_MATERIAL_READ);
                appear.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
                Vector3f pos= new Vector3f();
//              trans.get(pos);         x= (int)pos.x;                        z= (int)pos.z;
                cone= new Cone(.25f, 1f, Cone.GENERATE_TEXTURE_COORDS | Cone.GENERATE_NORMALS, 4, 4, a);
                cone.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
                cone.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
        }
}//class grass

//class entry
class Entry{
        int num;
        long time;

        Entry(int n, long t){
                num= n;
                time= t;
        }
}//class Entry

//class AnimalRotator
class AnimalRotator{
        BranchGroup localU, animal;
        TransformGroup localT, t;
        Transform3D local3D= new Transform3D(), trans3D= new Transform3D();
	
        public AnimalRotator(BranchGroup b, BranchGroup b2){
                animal= b;
                localU= b2;
                t= new TransformGroup();
                localT= new TransformGroup();
                if (t != null)
                        t.getTransform(trans3D);
                else{
                        t.setTransform(trans3D);
                }
                if (localT != null)
                        localT.getTransform(local3D);
                else{
                        localT.setTransform(local3D);
                }

                animal.addChild(t);
                localU.addChild(localT);
                localU.addChild(animal);
        }//constructor
}//class AnimalRotator